十分钟上手 Next.js
<h1 class="Post-Title">十分钟上手 Next.js</h1><div class="Post-Author">
<div class="AuthorInfo">
<div class="AuthorInfo">
<div class="css-1gomreu"><img src="https://pica.zhimg.com/v2-7fc3d5ed09d3768a98a519e659fa634f_l.jpg?source=172ae18b" srcset="https://pica.zhimg.com/v2-7fc3d5ed09d3768a98a519e659fa634f_l.jpg?source=172ae18b 2x" alt="写代码的海怪" class="Avatar AuthorInfo-avatar css-1y9jkzv"></div>
<div class="AuthorInfo-content">
<div class="AuthorInfo-head">
<div class="css-1gomreu">写代码的海怪</div>
<span class="UserLink AuthorInfo-name"><span class="css-18biwo"></span></span></div>
<div class="AuthorInfo-detail">
<div class="AuthorInfo-badge">
<div class="ztext AuthorInfo-badgeText css-0">腾讯 前端工程师</div>
</div>
</div>
</div>
</div>
</div>
<button class="Button FollowButton Button--primary Button--blue" type="button">关注他</button></div>
<div class="LabelContainer-wrapper"> </div>
<div><span class="Voters"><button class="Button Button--plain" type="button">28 人赞同了该文章</button></span></div>
<div class="Post-RichTextContainer">
<div class="css-1yuhvjn">
<div class="RichText ztext Post-RichText css-4em6pe">
<h2 data-first-child="">前言</h2>
<p data-pid="EUfWdvJo">Next.js 已经出来很久了,但是一直没机会看这个框架。</p>
<p data-pid="UIca7Ywg">以前一直在用 create-react-app 来创建 React 项目,奈何 CRA 实在太难用了,今天花了点时间扫了一下 Next.js 的官网,发现用起来还挺简单的。</p>
<h2>Next.js</h2>
<p data-pid="QiZ2z9qd">虽然 Next.js 总被人称为 SSR 框架,其实 Next.js 还提供了很多功能,比如官网列出来的这些:</p>
<img src="https://pic1.zhimg.com/80/v2-7df9fc5af7a0b1a7cefeede0f4a820c0_1440w.webp" width="1028" height="952" class="origin_image zh-lightbox-thumb lazy" data-caption="" data-size="normal" data-rawwidth="1028" data-rawheight="952" data-original="https://pic1.zhimg.com/v2-7df9fc5af7a0b1a7cefeede0f4a820c0_r.jpg" data-actualsrc="https://pic1.zhimg.com/v2-7df9fc5af7a0b1a7cefeede0f4a820c0_b.jpg" data-lazy-status="ok">
<p data-pid="PJzZydu0">所以说,Next.js 更像是一个框架,包含了路由、优化、SSR 等一系列功能。</p>
<h2>起步</h2>
<p data-pid="wfhey7jp">和 create-react-app 一样,Next.js 一样有个 create-next-app 的脚手架。</p>
<div class="highlight">
<pre><code class="language-text">create-next-app demo</code></pre>
</div>
<p data-pid="JaRiCVlP">使用上面命令后就可以创建一个 Next.js 框架的 React 项目。</p>
<h2>路由</h2>
<p data-pid="avTh1m6Z">Next.js 也提供了路由系统,采用名字约定路由</p>
<ul>
<li data-pid="5rlQN57H"><code>pages/index.js</code> 对应 <code>/</code></li>
<li data-pid="Kd1jgMrP"><code>pages/xxx/first.js</code> 对应 <code>/xxx/first</code></li>
</ul>
<p data-pid="MBsGKWTm">使用 <code>Link</code> 组件来做路由跳转</p>
<div class="highlight">
<pre><code class="language-js"><span class="kd">function <span class="nx">FirstPost<span class="p">() <span class="p">{
<span class="k">return <span class="p">(
<span class="o"><>
<span class="o"><<span class="nx">h1<span class="o">><span class="nx">First <span class="nx">Post<span class="o"><<span class="err">/h1>
<span class="o"><<span class="nx">h2<span class="o">>
<span class="o"><<span class="nx">Link <span class="nx">href<span class="o">=<span class="s2">"/"<span class="o">>
<span class="o"><<span class="nx">a<span class="o">><span class="nx">Back <span class="nx">to <span class="nx">home<span class="o"><<span class="err">/a>
<span class="o"><<span class="err">/Link>
<span class="o"><<span class="err">/h2>
<span class="o"><<span class="err">/>
<span class="p">)
<span class="p">}
</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></code></pre>
</div>
<p data-pid="yIBcN5pN">有的时候需要跳转到外链,可以使用 <code><a></code> 标签就可以。</p>
<h2>静态资源</h2>
<p data-pid="_bSfTYa4">静态资源用的最多的就是 图片 了,Next.js 提供了 <code>Image</code> 组件来替代 <code>img</code>。</p>
<p data-pid="ecKO9GNd"><code>Image</code> 组件的好处就是可以提高网页加载图片的性能,可以自动按需加载,当图片进入视图时再加载图片。</p>
<p data-pid="35zHRlZQ">除了相对路径引入,还可以将图片放在 <code>public/images/</code> 下,然后用 “绝对路径” 引入。</p>
<img src="https://pic2.zhimg.com/80/v2-e893e0930ac6aa07311aab109128a175_1440w.webp" width="142" height="89" class="content_image lazy" data-caption="" data-size="normal" data-rawwidth="142" data-rawheight="89" data-actualsrc="https://pic2.zhimg.com/v2-e893e0930ac6aa07311aab109128a175_b.png" data-lazy-status="ok">
<div class="highlight">
<pre><code class="language-js"><span class="kr">export <span class="k">default <span class="kd">function <span class="nx">Home<span class="p">() <span class="p">{
<span class="k">return <span class="p">(
<span class="o"><>
<span class="o"><<span class="nx">h1<span class="o">><span class="nx">My <span class="nx">Homepage<span class="o"><<span class="err">/h1>
<span class="o"><<span class="nx">Image
<span class="nx">src<span class="o">=<span class="s2">"/profile.jpg"
<span class="nx">alt<span class="o">=<span class="s2">"Picture of the author"
<span class="nx">width<span class="o">=<span class="p">{<span class="mi">500<span class="p">}
<span class="nx">height<span class="o">=<span class="p">{<span class="mi">500<span class="p">}
<span class="o">/>
<span class="o"><<span class="nx">p<span class="o">><span class="nx">Welcome <span class="nx">to <span class="nx">my <span class="nx">homepage<span class="o">!<<span class="err">/p>
<span class="o"><<span class="err">/>
<span class="p">)
<span class="p">}
</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></code></pre>
</div>
<h2>MetaData</h2>
<p data-pid="b_wZ1rZW">网页的 Meta Data 主要是指 <code><head></code> 元素里的内容,Next.js 直接提供了一个 <code><Head></code> 组件来包裹这些 Meta Data。</p>
<div class="highlight">
<pre><code class="language-js"><span class="o"><<span class="nx">Head<span class="o">>
<span class="o"><<span class="nx">title<span class="o">><span class="nx">First <span class="nx">Post<span class="o"><<span class="err">/title>
<span class="o"><<span class="err">/Head>
</span></span></span></span></span></span></span></span></span></span></span></span></code></pre>
</div>
<p data-pid="AQCQrgeg">好处就是可以在不同的页面组件里写不同的 Meta Data。</p>
<h2>CSS</h2>
<p data-pid="DulBsyU-">样式这一块和 <code>create-react-app</code> 差不多,使用 CSS module,命名为 <code>xxx.module.css</code> 就可以了,否则别的 CSS 文件都需要 <code>import 'xxx.css'</code> 来引入 CSS 样式。</p>
<p data-pid="jhYw8ZyQ">需要注意的是全局样式引入只能在 <code>pages/_app.js</code> 的根文件里引入。</p>
<p data-pid="OJsBe2u-">上述操作 Sass 同理。</p>
<h2>预渲染</h2>
<p data-pid="oyW51KZB">终于来到 Next.js 最引以为豪的 预渲染 了。Next.js 提供了三种渲染方式:</p>
<ul>
<li data-pid="aXMbvWe8">Client-side Rendering (CSR)</li>
<li data-pid="DlYiyzbg">Static Generation (SSG)</li>
<li data-pid="JxFEErWI">Server-side Rendering (SSR)</li>
</ul>
<h3>Client-side Rendering</h3>
<p data-pid="4ELubEd7">客户端渲染其实就是我们经常看到的前后端分离的场景了:只提供一个 html,拿到 <code><script></code> 的 JS 再去渲染页面。</p>
<div class="highlight">
<pre><code class="language-js"><span class="kr">import <span class="nx">useSWR <span class="nx">from <span class="s1">'swr'
<span class="kd">function <span class="nx">Profile<span class="p">() <span class="p">{
<span class="kr">const <span class="p">{ <span class="nx">data<span class="p">, <span class="nx">error <span class="p">} <span class="o">= <span class="nx">useSWR<span class="p">(<span class="s1">'/api/user'<span class="p">, <span class="nx">fetch<span class="p">)
<span class="k">if <span class="p">(<span class="nx">error<span class="p">) <span class="k">return <span class="o"><<span class="nx">div<span class="o">><span class="nx">failed <span class="nx">to <span class="nx">load<span class="o"><<span class="err">/div>
<span class="k">if <span class="p">(<span class="o">!<span class="nx">data<span class="p">) <span class="k">return <span class="o"><<span class="nx">div<span class="o">><span class="nx">loading<span class="p">...<span class="o"><<span class="err">/div>
<span class="k">return <span class="o"><<span class="nx">div<span class="o">><span class="nx">hello <span class="p">{<span class="nx">data<span class="p">.<span class="nx">name<span class="p">}<span class="o">!<<span class="err">/div>
<span class="p">}
</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></code></pre>
</div>
<p data-pid="nxNrjcGV">由于需要等加载到 JS 再渲染页面,所以这种渲染方式的有以下缺点: <em>SEO 不友好 </em>白屏时间较长</p>
<p data-pid="JlYQrypb">聪明的前端程序员就想:当访问 URL 的时候,我直接把数据都放到 HTML 上,那爬虫就可以直接拿到页面的信息,解决 SEO 的问题了,同样的不需要等 JS 加载完再发 Ajax 获取数据了,基础数据优先展示,也就能解决白屏时间过长的问题了。</p>
<p data-pid="bYWh0nHe">所以,预渲染说的就是 SSG 和 SSR。</p>
<h3>Static Generation</h3>
<p data-pid="V4bb60Iw">Static Generation 会在 build time 的 production 时候直接将数据写在 HTML 上,所以一般来说这些数据都是以静态、固定为主。</p>
<div class="highlight">
<pre><code class="language-js"><span class="kr">export <span class="nx">async <span class="kd">function <span class="nx">getStaticProps<span class="p">() <span class="p">{
<span class="kr">const <span class="nx">allPostsData <span class="o">= <span class="nx">getSortedPostsData<span class="p">()
<span class="k">return <span class="p">{
<span class="nx">props<span class="o">: <span class="p">{
<span class="nx">allPostsData
<span class="p">}
<span class="p">}
<span class="p">}
</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></code></pre>
</div>
<p data-pid="R3sOR98U">将 <code>getStaticProps</code> 这个函数 <code>export</code> 出来,里面则为 build time 时获取数据的逻辑。</p>
<h3>Server-side Rendering</h3>
<p data-pid="1zkpzNHo">通常情况下,我们很少使用静态的数据,一般以动态数据为主,不可能每次数据更新了又要打包一遍。所以就有了 Server-side Rendring。</p>
<p data-pid="xyrfvtCx">Server-side Rendering 则在每次 请求这个 URL 的时候,都会执行一次数据获取并生成 HTML 返回给前端。</p>
<blockquote data-pid="aIAhsa99">看到这里你可能会想 Next.js 和以前的 PHP、JSP 有什么区别么?都是吐 HTML 的呀。 Next.js 这里的 SSR 其实是同构渲染,即一套代码两端执行,具体区别请看这篇回答</blockquote>
<p data-pid="amUYmiBM">和 Static Generation 类似,Server-side Rendering 同样有一个对应的需要 <code>export</code> 出一个 <code>getServerSideProps</code> 函数。</p>
<div class="highlight">
<pre><code class="language-js"><span class="kr">export <span class="nx">async <span class="kd">function <span class="nx">getServerSideProps<span class="p">(<span class="nx">context<span class="p">) <span class="p">{
<span class="k">return <span class="p">{
<span class="nx">props<span class="o">: <span class="p">{
<span class="c1">// props for your component
<span class="c1"> <span class="p">}
<span class="p">}
<span class="p">}
</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></code></pre>
</div>
<h2>动态路由</h2>
<p data-pid="HYLO3xq4">所谓动态路由就是可以生成 <code>posts/:id</code> 这样的路由,<code>:id</code> 可以为 post 的 id。文件命名只需要写成 <code>.js</code> 就可以了。</p>
<p data-pid="EPnO7p8p">在页面组件文件里,可以通过前面说到的 <code>getStaticProps</code> 和 <code>getServerSideProps</code> 获取 params:</p>
<div class="highlight">
<pre><code class="language-js"><span class="kr">export <span class="nx">async <span class="kd">function <span class="nx">getStaticProps<span class="p">({ <span class="nx">params <span class="p">}) <span class="p">{
<span class="kr">const <span class="nx">postData <span class="o">= <span class="nx">getPostData<span class="p">(<span class="nx">params<span class="p">.<span class="nx">id<span class="p">)
<span class="k">return <span class="p">{
<span class="nx">props<span class="o">: <span class="p">{
<span class="nx">postData
<span class="p">}
<span class="p">}
<span class="p">}
</span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></code></pre>
</div>
<p data-pid="JfQ3lQ-_">其中,<code>pages/posts/[...id].js</code> 会匹配 <code>/posts/a/b</code> 路由和 <code>/posts/a</code>,<code>...</code> 为全匹配。</p>
<h2>API</h2>
<p data-pid="RFsG5fhP">除了正常写页面外,有时候我们还需要提供 API 接口,可以在 <code>pages/api</code> 下添加文件,文件名则为 API 名。</p>
<p data-pid="JVg-naSU">注意:不能在 <code>getStaticProps</code> 和 <code>getStaticPaths</code> 里添加 fetch 数据,因为他们只在 server side 运行,不会在 client side 运行,应该使用 helper function 来获取数据。</p>
<p data-pid="g7SiYTwq">API 代码将不会在 client side 的 bundle 里。</p>
<h2>部署</h2>
<p data-pid="YedAv7Dw">部署这一块 Next.js 推荐使用 Vercel 来部署。</p>
<p data-pid="qYtUxSt1">因为 Vercel 本身就是为 Next.js 服务的,所以只需要连上 Github Repo 就可以一键部署了。</p>
<h2>总结</h2>
<p data-pid="LTPTbj4B">稍微总结一下,Next.js 提供的有如下功能:</p>
<ul>
<li data-pid="NmloY8Hn"><code>Link</code> 组件,方便路由</li>
<li data-pid="wEf3W32W"><code>Image</code> 组件,优化图片加载</li>
<li data-pid="_jpwiAyE">文件路径生成路由机制,动态路由使用 <code>.js</code> 这样的命令</li>
<li data-pid="DkUuMoWA">SSR、SSG 的同构开发模式(其实就是 export 一个对应名字的函数,在里面提前获取数据就好了)</li>
<li data-pid="WHb4N_9f">样式方面和 <code>create-react-app</code> 差不多</li>
</ul>
</div>
</div>
</div>
</div>
<div id="MySignature" role="contentinfo">
漫思<br><br>
来源:https://www.cnblogs.com/sexintercourse/p/16858887.html
頁:
[1]