本文档适用于 Next.js 的 9.3 及以上版本。如果你使用的是 Next.js 的旧版本,请参考我们之前的文档。

在 Next.js 中,页面是由 pages 目录中的 .js、.jsx、.ts 或 .tsx 文件导出的 React 组件。每个页面都根据其文件名与一个路由相关联。

例如。如果你创建了 pages/about.js,像下面这样导出了一个 React 组件,它将在 / about 被访问。

  1. function About() {
  2. return <div>About</div>
  3. }
  4. export default About

带有动态路由的页面

Next.js 支持带有动态路由的页面。例如,如果你创建了一个名为 pages/posts/[id].js 的文件,那么它就可以在 post/1、post/2 等地方访问。

要了解更多关于动态路由的信息,请查看动态路由文档。

预渲染

默认情况下,Next.js 会对每个页面进行预渲染。这意味着 Next.js 会提前为每个页面生成 HTML,而不是由客户端的 JavaScript 完成。预渲染可以带来更好的性能和 SEO。

每个生成的 HTML 都与该页面所需的最小 JavaScript 代码相关联。当一个页面被浏览器加载时,它的 JavaScript 代码就会运行,并使该页面完全互动。(这个过程被称为水化)。

两种形式的预渲染

Next.js 有两种形式的预渲染。静态生成和服务器端渲染。区别在于它何时为一个页面生成 HTML。

  • 静态生成(推荐)。HTML 是在构建时生成的,并将在每次请求中重复使用。
  • 服务器端渲染。HTML 是在每次请求时生成的。

重要的是,Next.js 允许你选择你想在每个页面使用的预渲染形式。你可以通过对大多数页面使用 “静态生成”,而对其他页面使用 “服务器端渲染” 来创建一个 “混合”Next.js 应用程序。

出于性能的考虑,我们建议使用静态生成而不是服务器端渲染。静态生成的页面可以被 CDN 缓存,而不需要额外的配置来提高性能。然而,在某些情况下,服务器端渲染可能是唯一的选择。

你也可以在使用静态生成或服务器端渲染的同时使用客户端渲染。这意味着一个页面的某些部分可以完全由客户端的 JavaScript 来渲染。要了解更多,请看数据获取文档。

静态生成(推荐)。

实例

  • WordPress 实例(演示)
  • 使用 markdown 文件的 Blog Starter (Demo)
  • DatoCMS 实例(演示)
  • TakeShape 示例(演示)
  • Sanity 实例(演示)
  • Prismic 示例(演示)
  • Contentful 示例(演示)
  • Strapi 实例(演示)
  • Prepr 实例(演示)
  • Agility CMS 实例(演示)
  • 宇宙的例子(演示)
  • ButterCMS 实例(演示)
  • Storyblok 实例(演示)
  • GraphCMS 实例(演示)
  • Kontent 实例(演示)
  • 静态鸣叫(演示)

如果一个页面使用了静态生成,页面的 HTML 是在构建时生成的。这意味着在生产中,页面的 HTML 是在你运行下一次构建时生成的。然后这个 HTML 将在每次请求中被重复使用。它可以由 CDN 进行缓存。

在 Next.js 中,你可以静态地生成带或不带数据的页面。让我们来看看每种情况。

无数据的静态生成

默认情况下,Next.js 使用静态生成预渲染页面,不获取数据。下面是一个例子。

  1. function About() {
  2. return <div>About</div>
  3. }
  4. export default About

请注意,这个页面不需要获取任何外部数据来进行预渲染。在这样的情况下,Next.js 会在构建时为每个页面生成一个 HTML 文件。

有数据的静态生成

有些页面需要获取外部数据来进行预渲染。这有两种情况,一种或两种都可能适用。在每种情况下,你都可以使用 Next.js 提供的这些功能。

  1. 你的页面内容依赖于外部数据。使用 getStaticProps。
  2. 你的页面路径依赖于外部数据。使用 getStaticPaths(通常是在 getStaticProps 之外)。

情况 1:你的页面内容依赖于外部数据

例如。你的博客页面可能需要从 CMS(内容管理系统)中获取博客文章的列表。

  1. function Blog({ posts }) {
  2. return (
  3. <ul> {posts.map((post) => (
  4. <li>{post.title}</li>
  5. ))} </ul>
  6. )
  7. }
  8. export default Blog

为了在预渲染时获取这些数据,Next.js 允许你从同一文件中导出一个名为 getStaticProps 的异步函数。这个函数在构建时被调用,让你在预渲染时将获取的数据传递给页面的 props。

  1. function Blog({ posts }) {
  2. }
  3. export async function getStaticProps() {
  4. const res = await fetch('https://.../posts')
  5. const posts = await res.json()
  6. return {
  7. props: {
  8. posts,
  9. },
  10. }
  11. }
  12. export default Blog

要了解更多关于 getStaticProps 的工作原理,请查看数据获取文档。

情景 2:你的页面路径依赖于外部数据

Next.js 允许你创建具有动态路线的页面。例如,你可以创建一个名为 pages/posts/[id].js 的文件,以显示基于 id 的单一博客文章。这将允许你在访问 posts/1 时显示一个 id 为:1 的博客文章。

要了解更多关于动态路由的信息,请查看动态路由的文档。

然而,你想在构建时预渲染哪个 id 可能取决于外部数据。

例如:假设你在数据库中只添加了一篇博客文章(ID 为 1)。在这种情况下,你只想在构建时对 post/1 进行预渲染。

后来,你可能会添加第二篇文章(ID:2),那么你也会想对 post/2 进行预渲染。

因此,你的预渲染的页面路径取决于外部数据。为了处理这个问题,Next.js 让你从一个动态页面(本例中为 pages/posts/[id].js)导出一个名为 getStaticPaths 的异步函数。这个函数在构建时被调用,并让你指定你想要预渲染的路径。

  1. export async function getStaticPaths() {
  2. const res = await fetch('https://.../posts')
  3. const posts = await res.json()
  4. const paths = posts.map((post) => ({
  5. params: { id: post.id },
  6. }))
  7. return { paths, fallback: false }
  8. }

另外,在 pages/posts/[id].js 中,你需要导出 getStaticProps,这样你就可以用这个 id 获取关于帖子的数据,并使用它来预渲染页面。

  1. function Post({ post }) {
  2. }
  3. export async function getStaticPaths() {
  4. }
  5. export async function getStaticProps({ params }) {
  6. const res = await fetch(`https://.../posts/${params.id}`)
  7. const post = await res.json()
  8. return { props: { post } }
  9. }
  10. export default Post

要了解更多关于 getStaticPaths 的工作原理,请查看数据获取文档。

我应该在什么时候使用静态生成?

我们建议尽可能使用静态生成(有数据和无数据),因为你的页面可以一次建成并由 CDN 提供,这比每次请求时由服务器渲染页面要快得多。

你可以为许多类型的页面使用静态生成,包括。

  • 营销页面
  • 博客文章和作品集
  • 电子商务产品列表
  • 帮助和文档

你应该问自己。”我可以在用户的要求之前预先渲染这个页面吗?” 如果答案是肯定的,那么你应该选择静态生成。

另一方面,如果你不能在用户要求之前预先渲染一个页面,那么静态生成就不是一个好主意。也许你的页面显示的是经常更新的数据,而且每次请求时页面内容都会改变。

在这样的情况下,你可以采取以下措施。

  • 使用静态生成与客户端渲染。你可以跳过预渲染页面的某些部分,然后使用客户端的 JavaScript 来填充它们。要了解更多关于这种方法的信息,请查看数据获取文档。
  • 使用服务器端渲染。Next.js 在每次请求时都会预先渲染一个页面。这将会比较慢,因为页面不能被 CDN 缓存,但预渲染的页面将始终是最新的。我们将在下面讨论这种方法。

服务器端渲染

也被称为 “SSR” 或 “动态渲染”。

如果一个页面使用了服务器端渲染,页面的 HTML 会在每次请求时生成。

要对一个页面使用服务器端渲染,你需要导出一个叫做 getServerSideProps 的异步函数。这个函数将在每次请求时被服务器调用。

例如,假设你的页面需要对经常更新的数据(从外部 API 获取)进行预渲染。你可以编写 getServerSideProps 来获取这些数据并将其传递给 Page,如下所示。

  1. function Page({ data }) {
  2. }
  3. export async function getServerSideProps() {
  4. const res = await fetch(`https://.../data`)
  5. const data = await res.json()
  6. return { props: { data } }
  7. }
  8. export default Page

正如你所看到的,getServerSideProps 与 getStaticProps 类似,但不同的是,getServerSideProps 是在每次请求时运行,而不是在构建时运行。

要了解更多关于 getServerSideProps 的工作原理,请查看我们的数据获取文档。

总结

我们已经讨论了 Next.js 的两种预渲染形式。

  • 静态生成(推荐)。HTML 是在构建时生成的,并将在每次请求中重复使用。要使一个页面使用静态生成,要么导出页面组件,要么导出 getStaticProps(如果需要的话,还有 getStaticPaths)。它非常适用于那些可以在用户请求前预先渲染的页面。你也可以把它和客户端渲染一起使用,以带来额外的数据。
  • 服务器端渲染。HTML 是在每个请求中生成的。要使一个页面使用服务器端渲染,请导出 getServerSideProps。因为服务器端渲染会导致比静态生成更慢的性能,所以只有在绝对必要时才使用。

了解更多

我们建议你接下来阅读以下章节。
https://nextjs.org/docs/basic-features/pages