Skip to main content

getStaticProps

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

pages/index.tsx
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 中在客户端查看。这是为了允许页面正确水合。确保你不要在 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 在后台按需运行

当与增量静态再生成结合使用时,getStaticProps 将在后台运行,同时重新验证旧页面,并向浏览器提供新页面。

getStaticProps 无法访问传入的请求(例如查询参数或 HTTP 头),因为它生成静态 HTML。如果你需要为页面访问请求,请考虑在 getStaticProps 之外使用中间件

使用 getStaticProps 从 CMS 获取数据

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

pages/blog.tsx
// 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 中编写服务端代码,而不是从 getStaticProps 获取 API 路由(它本身从外部源获取数据)。

以下面的例子为例。使用 API 路由从 CMS 获取一些数据。然后从 getStaticProps 直接调用该 API 路由。这会产生额外的调用,降低性能。相反,可以通过使用 lib/ 目录共享从 CMS 获取数据的逻辑。然后可以与 getStaticProps 共享。

lib/load-posts.js
// 以下函数在 `lib/` 目录中
// 与 getStaticProps 和 API 路由共享
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() {
// 你可以直接在 `getStaticProps` 中调用相同的函数
// 而不是获取你的 `/api` 路由
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 导出为独立函数 —— 如果你将 getStaticProps 添加为页面组件的属性,它将不会工作。

提示:如果你创建了自定义 app,请确保按照链接文档中所示将 pageProps 传递给页面组件,否则 props 将为空。

在开发环境中每次请求时运行

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

预览模式

你可以使用预览模式临时绕过静态生成,在请求时而不是构建时渲染页面。例如,你可能正在使用无头 CMS,并希望在发布之前预览草稿。