getStaticProps

如果从页面导出一个名为 getStaticProps 的函数(静态站点生成),Next.js 将在构建时使用该函数返回的 props 预渲染此页面。

import type { InferGetStaticPropsType, GetStaticProps } from 'next'

type Repo = {
  name: string
  stargazers_count: number
}

export const getStaticProps = (async (context) => {
  const res = await fetch('https://api.github.com/repos/vercel/next.js')
  const repo = await res.json()
  return { props: { repo } }
}) satisfies GetStaticProps<{
  repo: Repo
}>

export default function Page({
  repo,
}: InferGetStaticPropsType<typeof getStaticProps>) {
  return repo.stargazers_count
}

请注意,无论采用何种渲染类型,所有 props 都会传递给页面组件,并可在初始 HTML 的客户端查看。这是为了让页面能正确进行水合 (hydrate)。请确保不要在 props 中传递任何不应在客户端可用的敏感信息。

getStaticProps API 参考文档涵盖了可与 getStaticProps 一起使用的所有参数和 props。

何时应使用 getStaticProps?

在以下情况下应使用 getStaticProps

  • 渲染页面所需的数据在用户请求之前的构建时即可获取
  • 数据来自无头 CMS
  • 页面必须预渲染(出于 SEO 目的)且速度极快 —— getStaticProps 会生成 HTMLJSON 文件,两者均可由 CDN 缓存以提高性能
  • 数据可公开缓存(非用户特定)。在某些特定情况下,可通过使用中间件重写路径绕过此条件

getStaticProps 何时运行

getStaticProps 始终在服务端运行,而不会在客户端运行。您可以使用此工具验证 getStaticProps 内的代码已从客户端包中移除。

  • getStaticProps 始终在 next build 期间运行
  • 使用 fallback: true 时,getStaticProps 会在后台运行
  • 使用 fallback: blocking 时,getStaticProps 会在初始渲染前调用
  • 使用 revalidate 时,getStaticProps 会在后台运行
  • 使用 revalidate() 时,getStaticProps 会根据需求在后台运行

增量静态再生 (Incremental Static Regeneration) 结合使用时,getStaticProps 会在重新验证过期页面的同时在后台运行,并将新页面提供给浏览器。

getStaticProps 无法访问传入的请求(如查询参数或 HTTP 标头),因为它生成的是静态 HTML。如果页面需要访问请求,可考虑在使用 getStaticProps 的同时配合使用中间件 (Middleware)

使用 getStaticProps 从 CMS 获取数据

以下示例展示如何从 CMS 获取博客文章列表。

// posts 将在构建时由 getStaticProps() 填充
export default function Blog({ posts }) {
  return (
    <ul>
      {posts.map((post) => (
        <li>{post.title}</li>
      ))}
    </ul>
  )
}

// 此函数在构建时于服务端调用
// 不会在客户端调用,因此甚至可以直接执行数据库查询
export async function getStaticProps() {
  // 调用外部 API 端点获取文章
  // 可使用任何数据获取库
  const res = await fetch('https://.../posts')
  const posts = await res.json()

  // 通过返回 { props: { posts } },Blog 组件
  // 将在构建时接收 `posts` 作为 prop
  return {
    props: {
      posts,
    },
  }
}

getStaticProps API 参考文档涵盖了可与 getStaticProps 一起使用的所有参数和 props。

直接编写服务端代码

由于 getStaticProps 仅在服务端运行,因此永远不会在客户端运行。它甚至不会包含在浏览器的 JS 包中,因此您可以编写直接的数据库查询而无需担心它们被发送到浏览器。

这意味着无需从 getStaticProps 中获取API 路由(该路由本身从外部源获取数据),您可以直接在 getStaticProps 中编写服务端代码。

请看以下示例。API 路由用于从 CMS 获取数据,然后直接从 getStaticProps 调用该 API 路由。这会增加额外的调用,降低性能。相反,可以通过使用 lib/ 目录共享从 CMS 获取数据的逻辑,然后与 getStaticProps 共享。

lib/load-posts.js
// 以下函数与 getStaticProps 和 API 路由共享
// 来自 `lib/` 目录
export async function loadPosts() {
  // 调用外部 API 端点获取文章
  const res = await fetch('https://.../posts/')
  const data = await res.json()

  return data
}
pages/blog.js
// pages/blog.js
import { loadPosts } from '../lib/load-posts'

// 此函数仅在服务端运行
export async function getStaticProps() {
  // 无需获取 `/api` 路由,可以直接在 `getStaticProps` 中调用相同函数
  const posts = await loadPosts()

  // 返回的 props 将传递给页面组件
  return { props: { posts } }
}

或者,如果您没有使用 API 路由获取数据,则可以直接在 getStaticProps 中使用 fetch() API 获取数据。

要验证 Next.js 从客户端包中移除了哪些内容,可以使用 next-code-elimination 工具

静态生成 HTML 和 JSON

当使用 getStaticProps 的页面在构建时预渲染时,除了页面 HTML 文件外,Next.js 还会生成一个包含 getStaticProps 运行结果的 JSON 文件。

此 JSON 文件将通过 next/linknext/router 用于客户端路由。当导航到使用 getStaticProps 预渲染的页面时,Next.js 会获取此 JSON 文件(在构建时预计算)并将其用作页面组件的 props。这意味着客户端页面转换不会调用 getStaticProps,因为只使用导出的 JSON。

使用增量静态生成时,getStaticProps 将在后台执行以生成客户端导航所需的 JSON。您可能会看到对同一页面发出多个请求,但这是预期的,不会影响最终用户的性能。

可在何处使用 getStaticProps

getStaticProps 只能从页面导出。您不能从非页面文件、_app_document_error 中导出它。

这一限制的原因之一是 React 需要在页面渲染前获取所有必需的数据。

此外,必须将 getStaticProps 作为独立函数导出 —— 如果将其添加为页面组件的属性,则不会生效。

须知:如果您创建了自定义应用 (custom app),请确保按照链接文档所示将 pageProps 传递给页面组件,否则 props 将为空。

开发环境中的每次请求运行

在开发环境(next dev)中,getStaticProps 会在每次请求时调用。

预览模式

您可以使用预览模式 (Preview Mode) 临时绕过静态生成,在请求时而非构建时渲染页面。例如,您可能正在使用无头 CMS 并希望在草稿发布前预览它们。

On this page