页面(Pages)

Next.js 中,一个 page(页面) 就是一个从 .js、jsx、.ts 或 .tsx 文件导出(export)的 React 组件 ,这些文件存放在 pages 目录下。每个 page(页面)都使用其文件名作为路由(route)。

预渲染

默认情况下,Next.js 将 预渲染 每个 page(页面)。这意味着 Next.js 会预先为每个页面生成 HTML 文件,而不是由客户端 JavaScript 来完成。预渲染可以带来更好的性能和 SEO 效果。

每个生成的 HTML 文件都与该页面所需的最少 JavaScript 代码相关联。当浏览器加载一个 page(页面)时,其 JavaScript 代码将运行并使页面完全具有交互性。(此过程称为 水合(hydration)。)

需要获取数据的静态生成

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

  • 您的页面 内容 取决于外部数据:使用 getStaticProps
  • 你的页面 paths(路径) 取决于外部数据:使用 getStaticPaths (通常还要同时使用 getStaticProps)。

场景 1: 页面 内容 取决于外部数据

import React from "react";

/**
 * 定义数据类型
 */
export interface iListHome {
  id: number;
  title: string;
  create_at: number;
}

/**
 * 组件
 * @param props
 * @returns
 */
export default function home(props: { list: Array<iListHome> }) {
  const { list } = props;
  return (
    <>
      <div>home next</div>
      <div>
        <ul>
          {list?.length &&
            list.map((_item: iListHome) => {
              return (
                <li key={_item.id}>
                  id: {_item.id} --- title: {_item.title} ---- @{" "}
                  {_item.create_at}
                </li>
              );
            })}
        </ul>
      </div>
    </>
  );
}

/**
 * 模拟数据
 * @returns
 */
export async function mockData(): Promise<Array<iListHome>> {
  return [
    { id: 1, title: "first title", create_at: 121929109 },
    { id: 2, title: "first second", create_at: 121929122 },
    { id: 3, title: "first third", create_at: 121929133 },
  ];
}

/**
 * 静态生成
 * @returns
 */
export async function getStaticProps() {
  const list = await mockData();
  return {
    props: {
      list,
    },
  };
}

场景 2:页面路径取决于外部数据


// 输出组件
export default function Post({ post }) {
  // Render post...
}

// 此函数在构建时被调用
export async function getStaticPaths() {
  // 调用外部 API 获取博文列表
  const res = await fetch('https://.../posts')
  const posts = await res.json()

  // 据博文列表生成所有需要预渲染的路径
  const paths = posts.map((post) => ({
    params: { id: post.id },
  }))

  // We'll pre-render only these paths at build time.
  // { fallback: false } means other routes should 404.
  return { paths, fallback: false }
}

// 在构建时也会被调用
export async function getStaticProps({ params }) {
  // params 包含此片博文的 `id` 信息。
  // 如果路由是 /posts/1,那么 params.id 就是 1
  const res = await fetch(`https://.../posts/${params.id}`)
  const post = await res.json()

  // 通过 props 参数向页面传递博文的数据
  return { props: { post } }
}

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

我们建议您尽可能使用 静态生成 (带有或不带数据),因为你的所有 page(页面)都可以只构建一次并托管到 CDN 上,这比让服务器根据每个页面请求来渲染页面快得多。

还可以对多种类型的页面使用“静态生成”,包括:

- 营销页面
- 博客文章和个人简历
- 电商产品列表
- 帮助和文档

您应该问问自己:“我可以在用户请求之前预先渲染此页面吗?” 如果答案是肯定的,则应选择“静态生成”。

另一方面,如果你无法在用户请求之前预渲染页面,则“静态生成” 不是 一个好主意。这也许是因为你的页面需要显示频繁更新的数据,并且页面内容会随着每个请求而变化。

在这种情况下,您可以执行以下任一操作:

- 将“静态生成”与 客户端渲染 一起使用:你可以跳过页面某些部分的预渲染,然后使用客户端 JavaScript 来填充它们。要了解有关此方法的更多信息,请查看 获取数据 章节的文档。
- 使用 服务器端渲染: Next.js 针对每个页面的请求进行预渲染。由于 CDN 无法缓存该页面,因此速度会较慢,但是预渲染的页面将始终是最新的。我们将在下面讨论这种方法。