Next.js - App Router Vs. Pages Router 详细对比

多年来,我们将页面放置在 Next 的“pages”目录中。
现在这种情况即将改变。

不久前,Next.js 推出了新的 App Router,显着改变了我们创建页面的方式。 但不仅是我们存储应用程序页面的目录发生了变化,而且可用的功能也发生了变化。

我们的下一个项目过去是这样的:

└── pages
    ├── about.js
    ├── index.js
    └── team.js

使用 App Router,我们的应用程序的结构看起来类似于:

src/
└── app
    ├── about
    │   └── page.js
    ├── globals.css
    ├── layout.js
    ├── login
    │   └── page.js
    ├── page.js 
    └── team
        └── route.js

创建应用程序的约定如下:

  • 应用中的每个页面都有自己的目录。目录名称定义 URL 路径。
  • 浏览器中访问路径时渲染的组件是 page.js。
  • 我们可以将其他组件存储在路径的目录中。 如果它们没有命名为 page.js,则不会影响路由。
  • 每个页面的目录中可以放置几个具有保留名称的文件。 它们都具有特定的功能。 例如,有loading.js、template.js 和layout.js——我们稍后将讨论后者。

到目前为止,一切都很好; 我们已经介绍了这些约定。
正如您所知,现有应用程序需要进行轻微的重构。 但这样做的动机是什么? 以下是 App Router 中可用的新功能。

App Router 功能介绍

Vercel 最近宣布了一些很棒的功能。 其中大多数是 App Router 独有的 - 它们不能在经典的 Pages Router 中使用。
以下是我们现在可以做的令人兴奋的事情的列表。

客户端和服务器组件 (Client and server components)

默认情况下,应用程序目录中的任何组件现在都是服务器组件。 但是,这是什么意思? 下面是一个小回顾。

服务器组件在服务器上呈现。 他们的所有代码都保留在服务器上 - 这意味着我们无法使用客户端功能,例如窗口对象或 React 中的典型钩子。 服务器组件缺乏与客户端的交互性。 当仅仅定义一个钩子时,它们甚至会失败:

客户端组件与我们在 Next.js 中使用的先前类型的组件相反且相似。 他们可以使用浏览器、提供交互性并将其 JS 代码发送到客户端。
虽然 App Router 中的所有组件默认都是服务器组件,但可以通过在文件顶部声明“使用客户端”来声明客户端组件。
这种区别仅适用于新的应用程序路由器。 以下是一个快速概述:

客户端组件:

  • 浏览器API
  • 事件监听器
  • 所有 React 钩子
  • 非常适合在客户端生成一堆 HTML

服务器组件:

  • 非常适合隐藏代码和秘密
  • 不要传送大部分依赖项
  • 直接访问后台
  • 完全集成服务器操作

布局更简单(Easier layouting)

我已经提到了layout.js 文件,它可以位于每个路径的目录中。 该组件使布局变得简单,因为路径组件会自动应用于提供的布局。 让我们看一个例子。

在我们选择的路径目录中,我们创建一个 layout.js:

// layout.js

export default function LoginLayout({ children }) {
  return <div className='login-area'>{children}</div>
}

它所需要做的就是渲染一个自动传递的子组件 - 该子组件是 page.js 组件。
page.js 完全取决于我们。 由于布局是自动应用的,因此我们不需要在此文件中指定引用任何内容。

嵌套布局(Nested layouts)

新的布局文件还有更多内容。 布局组件可以应用于多个页面。 如果子目录没有单独指定布局,则使用顶级布局。
这是一个例子:

src/
└── app
    ├── market
    │   ├── buy
    │   │   └── page.js
    │   ├── sell
    │   │   └── page.js
    │   ├── layout.js

页面“/buy”和“/sell”具有相同的布局。

服务器动作(Server actions)

目前,服务器操作仍然是一个实验性功能。
它们可以根据客户端上的事件轻松执行服务器端代码:

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>
 )
}

按下按钮,serverAction 函数就会被执行。
这时,需要在config中启用服务器操作。

const nextConfig = {
 experimental: {
  serverActions: true,
 },
}

拦截路由(Intercepting routes)

拦截路由顾名思义:拦截路由请求。 此功能使我们能够构建根据其他一些因素表现不同的页面。
Vercel 自己实现了一个令人兴奋的示例:https://nextgram.vercel.app/
当您单击图库中的图像时,它会作为模式打开 - 而且路径也会发生变化,从而寻址到确切的图像。

如果刷新页面,它将呈现为独立页面。 然而,道路并没有改变。 由于路由被拦截,我们对同一路径收到不同的行为:

并行路由(Parallel routing)

平行路线与拦截路线结合使用时最为有效。 并行路由功能本身听起来并不太令人兴奋:

并行路由允许您同时或有条件地在同一布局中渲染一个或多个页面

  • 官方文档

该功能非常适合组合两个或多个可以独立查看的页面。 这些页面仍然是独立的 - 因此,即使在同一 URL 上呈现,它们也具有单独的代码。

页面路由器(Pages Router)

页面与应用程序路由器并不是一场平等的争论。 相反,应用程序路由器是下一步,并且应该成为构建应用程序的标准方式。
一些受人喜爱的功能与 Pages Router 绑定在一起,因此不会占上风:

  • getStaticProps
  • getServerSideProps
  • getStaticPaths
  • Custom document component(自定义文档组件)
  • Custom app component(自定义应用程序组件)
  • next/head

好消息是这两条路线可以同时使用。 Vercel 甚至建议在迁移时保留页面路由器,以免破坏任何内容。
我们的自定义文档和应用程序组件可以替换为根布局。
以 SEO 为中心的 next/head 组件是完全多余的。 新的应用程序路由器提供了对元数据的内置支持,如下所示:

import { Metadata } from 'next'
 
export const metadata: Metadata = {
  title: 'Hello World',
}
 
export default function Page() {
  return <></>
}

函数 getStaticPropsgetServerSidePropsgetStaticPaths 可以被新的服务器动作(Server Actions)替换。

性能(Performance)

当谈到页面与应用程序路由器的性能之争时,我们看到了一些有趣的事情。 应用程序路由器的性能较差。
为了进行简单的基准测试,我创建了两个执行相同操作的项目:渲染由 URL 传递的许多 HTML 标签。
结果如下:

特别是对于 100 个和 1000 个呈现的标签,百分比差异相当大(App Router 的性能低)。 令人着迷的是,随着标签的增多,两种表现似乎变得更加接近。
该基准测试的灵感来自 Jack Herrington,我建议您查看他的深入性能视频。
https://youtu.be/3Q2q2gs0nAI

总结(Summary)

久而久之,我们就要和新路由器交朋友了。
虽然从页面过渡到新方法需要一些工作,但新功能是值得的。 然而,如果您对其功能感到满意,现有的路由器可能仍然是新项目的解决方案。
对于潜在的弃用,我并没有压力。 对页面路由器的支持可能始终存在,因为 Next.js 已经为这两个模型提供了两份单独的文档。 然而,新功能可能会成为应用程序路由器独有的。

感谢您的阅读!
有关新 App Router 及其功能的更多信息:
https://louispetrik.medium.com/what-to-watch-out-for-when-using-nexts-new-server-actions-ffae2262b12a

ref:
https://javascript.plainenglish.io/next-jss-new-app-vs-pages-router-a-detailed-comparison-46f846963af5

posted @ 2023-08-10 18:18  炎黄子孙,龙的传人  阅读(4958)  评论(0编辑  收藏  举报