Next.js - App Router Vs. Pages Router 详细对比
<p><img src="https://img2023.cnblogs.com/blog/1344547/202308/1344547-20230810172832043-121209679.png"></p><p>多年来,我们将页面放置在 Next 的“pages”目录中。<br>
现在这种情况即将改变。</p>
<p>不久前,Next.js 推出了新的 App Router,显着改变了我们创建页面的方式。 但不仅是我们存储应用程序页面的目录发生了变化,而且可用的功能也发生了变化。</p>
<p>我们的下一个项目<strong>过去</strong>是这样的:</p>
<pre><code>└── pages
├── about.js
├── index.js
└── team.js
</code></pre>
<p>使用 App Router,我们的应用程序的结构看起来类似于:</p>
<pre><code>src/
└── app
├── about
│ └── page.js
├── globals.css
├── layout.js
├── login
│ └── page.js
├── page.js
└── team
└── route.js
</code></pre>
<p>创建应用程序的约定如下:</p>
<ul>
<li>应用中的每个页面都有自己的目录。目录名称定义 URL 路径。</li>
<li>浏览器中访问路径时渲染的组件是 page.js。</li>
<li>我们可以将其他组件存储在路径的目录中。 如果它们没有命名为 page.js,则不会影响路由。</li>
<li>每个页面的目录中可以放置几个具有保留名称的文件。 它们都具有特定的功能。 例如,有loading.js、template.js 和layout.js——我们稍后将讨论后者。</li>
</ul>
<p>到目前为止,一切都很好; 我们已经介绍了这些约定。<br>
正如您所知,现有应用程序需要进行轻微的重构。 但这样做的动机是什么? 以下是 App Router 中可用的新功能。</p>
<h1 id="app-router-功能介绍">App Router 功能介绍</h1>
<p>Vercel 最近宣布了一些很棒的功能。 其中大多数是 App Router 独有的 - 它们不能在经典的 Pages Router 中使用。<br>
以下是我们现在可以做的令人兴奋的事情的列表。</p>
<h2 id="客户端和服务器组件-client-and-server-components">客户端和服务器组件 (Client and server components)</h2>
<p>默认情况下,应用程序目录中的任何组件现在都是服务器组件。 但是,这是什么意思? 下面是一个小回顾。</p>
<p>服务器组件在服务器上呈现。 他们的所有代码都保留在服务器上 - 这意味着我们无法使用客户端功能,例如窗口对象或 React 中的典型钩子。 服务器组件缺乏与客户端的交互性。 当仅仅定义一个钩子时,它们甚至会失败:</p>
<p><img src="https://img2023.cnblogs.com/blog/1344547/202308/1344547-20230810173530779-1139651804.png"></p>
<p>客户端组件与我们在 Next.js 中使用的先前类型的组件相反且相似。 他们可以使用浏览器、提供交互性并将其 JS 代码发送到客户端。<br>
虽然 App Router 中的所有组件默认都是服务器组件,但可以通过在文件顶部声明“使用客户端”来声明客户端组件。<br>
这种区别仅适用于新的应用程序路由器。 以下是一个快速概述:</p>
<p>客户端组件:</p>
<ul>
<li>浏览器API</li>
<li>事件监听器</li>
<li>所有 React 钩子</li>
<li>非常适合在客户端生成一堆 HTML</li>
</ul>
<p>服务器组件:</p>
<ul>
<li>非常适合隐藏代码和秘密</li>
<li>不要传送大部分依赖项</li>
<li>直接访问后台</li>
<li>完全集成服务器操作</li>
</ul>
<h2 id="布局更简单easier-layouting">布局更简单(Easier layouting)</h2>
<p>我已经提到了layout.js 文件,它可以位于每个路径的目录中。 该组件使布局变得简单,因为路径组件会自动应用于提供的布局。 让我们看一个例子。</p>
<p>在我们选择的路径目录中,我们创建一个 layout.js:</p>
<pre><code class="language-tsx">// layout.js
export default function LoginLayout({ children }) {
return <div className='login-area'>{children}</div>
}
</code></pre>
<p>它所需要做的就是渲染一个自动传递的子组件 - 该子组件是 page.js 组件。<br>
page.js 完全取决于我们。 由于布局是自动应用的,因此我们不需要在此文件中指定引用任何内容。</p>
<h2 id="嵌套布局nested-layouts">嵌套布局(Nested layouts)</h2>
<p>新的布局文件还有更多内容。 布局组件可以应用于多个页面。 如果子目录没有单独指定布局,则使用顶级布局。<br>
这是一个例子:</p>
<pre><code>src/
└── app
├── market
│ ├── buy
│ │ └── page.js
│ ├── sell
│ │ └── page.js
│ ├── layout.js
</code></pre>
<p>页面“/buy”和“/sell”具有相同的布局。</p>
<h2 id="服务器动作server-actions">服务器动作(Server actions)</h2>
<p>目前,服务器操作仍然是一个实验性功能。<br>
它们可以根据客户端上的事件轻松执行服务器端代码:</p>
<pre><code class="language-tsx">export default function Home() {
async function serverAction() {
'use server'
console.log('server action executed')
}
return (
<form action={serverAction}>
<button type="submit">
Call server action
</button>
</form>
)
}
</code></pre>
<p>按下按钮,serverAction 函数就会被执行。<br>
这时,需要在config中启用服务器操作。</p>
<pre><code>const nextConfig = {
experimental: {
serverActions: true,
},
}
</code></pre>
<h2 id="拦截路由intercepting-routes">拦截路由(Intercepting routes)</h2>
<p>拦截路由顾名思义:拦截路由请求。 此功能使我们能够构建根据其他一些因素表现不同的页面。<br>
Vercel 自己实现了一个令人兴奋的示例:https://nextgram.vercel.app/<br>
当您单击图库中的图像时,它会作为模式打开 - 而且路径也会发生变化,从而寻址到确切的图像。</p>
<p><img src="https://img2023.cnblogs.com/blog/1344547/202308/1344547-20230810181037450-1448146978.png"></p>
<p>如果刷新页面,它将呈现为独立页面。 然而,道路并没有改变。 由于路由被拦截,我们对同一路径收到不同的行为:</p>
<p><img src="https://img2023.cnblogs.com/blog/1344547/202308/1344547-20230810181057963-360135691.png"></p>
<h2 id="并行路由parallel-routing">并行路由(Parallel routing)</h2>
<p>平行路线与拦截路线结合使用时最为有效。 并行路由功能本身听起来并不太令人兴奋:</p>
<blockquote>
<p>并行路由允许您同时或有条件地在同一布局中渲染一个或多个页面</p>
<ul>
<li>官方文档</li>
</ul>
</blockquote>
<p>该功能非常适合组合两个或多个可以独立查看的页面。 这些页面仍然是独立的 - 因此,即使在同一 URL 上呈现,它们也具有单独的代码。</p>
<h2 id="页面路由器pages-router">页面路由器(Pages Router)</h2>
<p>页面与应用程序路由器并不是一场平等的争论。 相反,应用程序路由器是下一步,并且应该成为构建应用程序的标准方式。<br>
一些受人喜爱的功能与 Pages Router 绑定在一起,因此不会占上风:</p>
<ul>
<li>getStaticProps</li>
<li>getServerSideProps</li>
<li>getStaticPaths</li>
<li>Custom document component(自定义文档组件)</li>
<li>Custom app component(自定义应用程序组件)</li>
<li>next/head</li>
</ul>
<p>好消息是这两条路线可以同时使用。 Vercel 甚至建议在迁移时保留页面路由器,以免破坏任何内容。<br>
我们的自定义文档和应用程序组件可以替换为根布局。<br>
以 SEO 为中心的 next/head 组件是完全多余的。 新的应用程序路由器提供了对元数据的内置支持,如下所示:</p>
<pre><code class="language-tsx">import { Metadata } from 'next'
export const metadata: Metadata = {
title: 'Hello World',
}
export default function Page() {
return <></>
}
</code></pre>
<p>函数 <code>getStaticProps</code>、<code>getServerSideProps</code> 和 <code>getStaticPaths</code> 可以被新的服务器动作(Server Actions)替换。</p>
<h2 id="性能performance">性能(Performance)</h2>
<p>当谈到页面与应用程序路由器的性能之争时,我们看到了一些有趣的事情:App Router 的性能较差。<br>
为了进行简单的基准测试,我创建了两个执行相同操作的项目:渲染由 URL 传递的许多 HTML 标签。<br>
结果如下:<br>
<img src="https://img2023.cnblogs.com/blog/1344547/202308/1344547-20230810181451097-746911109.png"><br>
特别是对于 100 个和 1000 个呈现的标签,百分比差异相当大(App Router 的性能低)。 令人着迷的是,随着标签的增多,两种表现似乎变得更加接近。<br>
该基准测试的灵感来自 Jack Herrington,我建议您查看他的深入性能视频。<br>
https://youtu.be/3Q2q2gs0nAI</p>
<h1 id="总结summary">总结(Summary)</h1>
<p>久而久之,我们就要和新路由器交朋友了。<br>
虽然从页面过渡到新方法需要一些工作,但新功能是值得的。 然而,如果您对其功能感到满意,现有的路由器可能仍然是新项目的解决方案。<br>
对于潜在的弃用,我并没有压力。 对页面路由器的支持可能始终存在,因为 Next.js 已经为这两个模型提供了两份单独的文档。 然而,新功能可能会成为应用程序路由器独有的。</p>
<p>有关新 App Router 及其功能的更多信息:<br>
https://louispetrik.medium.com/what-to-watch-out-for-when-using-nexts-new-server-actions-ffae2262b12a</p>
<p>ref:<br>
https://javascript.plainenglish.io/next-jss-new-app-vs-pages-router-a-detailed-comparison-46f846963af5</p>
<ul>
<li></li>
</ul><br><br>
来源:https://www.cnblogs.com/eddyz/p/17621208.html
頁:
[1]