Sponsor
ntab.devntab.dev 提升效率的新标签页组件
点击查看
Menu

getStaticProps

导出一个名为 getStaticProps 的函数将在构建时使用该函数返回的 props 预渲染页面:

pages/index.tsx
TypeScript
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
}

你可以在顶层作用域导入模块以在 getStaticProps 中使用。导入的模块不会被打包到客户端。这意味着你可以直接在 getStaticProps 中编写服务器端代码,包括从数据库获取数据。

Context 参数

context 参数是一个包含以下键的对象:

名称描述
params包含使用动态路由的页面的路由参数。例如,如果页面名称是 [id].js,那么 params 将类似于 { id: ... }。你应该将此与稍后解释的 getStaticPaths 一起使用。
preview(已弃用,改用 draftMode)如果页面处于预览模式,则为 true,否则为 false
previewData(已弃用,改用 draftMode)由 setPreviewData 设置的预览数据。
draftMode如果页面处于草稿模式,则为 true,否则为 false
locale包含活动语言环境(如果已启用)。
locales包含所有支持的语言环境(如果已启用)。
defaultLocale包含配置的默认语言环境(如果已启用)。
revalidateReason提供调用函数的原因。可以是以下之一:"build"(在构建时运行)、"stale"(重新验证周期已过期,或在开发模式下运行)、"on-demand"(通过按需重新验证触发)

getStaticProps 返回值

getStaticProps 函数应返回一个包含 propsredirectnotFound 的对象,后面可以跟一个可选的 revalidate 属性。

props

props 对象是键值对,每个值都被页面组件接收。它应该是一个可序列化的对象,以便可以使用 JSON.stringify 序列化所有传递的 props。

export async function getStaticProps(context) {
  return {
    props: { message: `Next.js 非常棒` }, // 将作为 props 传递给页面组件
  }
}

revalidate

revalidate 属性是页面重新生成可以发生的秒数(默认为 false 或不重新验证)。

// 此函数在服务器端构建时被调用。
// 如果启用了重新验证并且有新的请求,
// 它可能会在无服务器函数上再次被调用
export async function getStaticProps() {
  const res = await fetch('https://.../posts')
  const posts = await res.json()
 
  return {
    props: {
      posts,
    },
    // Next.js 将尝试重新生成页面:
    // - 当有请求时
    // - 每 10 秒最多一次
    revalidate: 10, // 以秒为单位
  }
}

了解更多关于增量静态重新生成的信息。

利用 ISR 的页面的缓存状态可以通过读取 x-nextjs-cache 响应头的值来确定。可能的值如下:

  • MISS - 路径不在缓存中(最多发生一次,在第一次访问时)
  • STALE - 路径在缓存中,但已超过重新验证时间,因此将在后台更新
  • HIT - 路径在缓存中,且未超过重新验证时间

notFound

notFound 布尔值允许页面返回 404 状态和 404 页面。使用 notFound: true,即使之前成功生成了页面,页面也将返回 404。这旨在支持用户生成的内容被作者删除等用例。注意,notFound 遵循此处描述的相同的重新验证行为。

export async function getStaticProps(context) {
  const res = await fetch(`https://.../data`)
  const data = await res.json()
 
  if (!data) {
    return {
      notFound: true,
    }
  }
 
  return {
    props: { data }, // 将作为 props 传递给页面组件
  }
}

值得注意的是:对于 fallback: false 模式,不需要 notFound,因为只有从 getStaticPaths 返回的路径才会被预渲染。

redirect

redirect 对象允许重定向到内部或外部资源。它应该匹配 { destination: string, permanent: boolean } 的形式。

在一些罕见的情况下,你可能需要为旧的 HTTP 客户端分配自定义状态码以正确重定向。在这些情况下,你可以使用 statusCode 属性而不是 permanent 属性,但不能同时使用。你还可以设置 basePath: false,类似于 next.config.js 中的重定向。

export async function getStaticProps(context) {
  const res = await fetch(`https://...`)
  const data = await res.json()
 
  if (!data) {
    return {
      redirect: {
        destination: '/',
        permanent: false,
        // statusCode: 301
      },
    }
  }
 
  return {
    props: { data }, // 将作为 props 传递给页面组件
  }
}

如果重定向在构建时是已知的,则应该在 next.config.js 中添加。

读取文件:使用 process.cwd()

可以在 getStaticProps 中直接从文件系统读取文件。

为此,你需要获取文件的完整路径。

由于 Next.js 将代码编译到一个单独的目录中,你不能使用 __dirname,因为它返回的路径与页面路由器不同。

相反,你可以使用 process.cwd(),它会给你 Next.js 执行的目录。

import { promises as fs } from 'fs'
import path from 'path'
 
// 文章将在构建时由 getStaticProps() 填充
function Blog({ posts }) {
  return (
    <ul>
      {posts.map((post) => (
        <li>
          <h3>{post.filename}</h3>
          <p>{post.content}</p>
        </li>
      ))}
    </ul>
  )
}
 
// 此函数在构建时在服务器端调用。
// 它不会在客户端调用,所以你甚至可以
// 直接进行数据库查询。
export async function getStaticProps() {
  const postsDirectory = path.join(process.cwd(), 'posts')
  const filenames = await fs.readdir(postsDirectory)
 
  const posts = filenames.map(async (filename) => {
    const filePath = path.join(postsDirectory, filename)
    const fileContents = await fs.readFile(filePath, 'utf8')
 
    // 通常你会解析/转换内容
    // 例如,你可以在这里将 markdown 转换为 HTML
 
    return {
      filename,
      content: fileContents,
    }
  })
  // 通过返回 { props: { posts } },Blog 组件
  // 将在构建时接收 `posts` 作为 prop
  return {
    props: {
      posts: await Promise.all(posts),
    },
  }
}
 
export default Blog

版本历史

版本变更
v13.4.0App Router 现在稳定,并简化了数据获取
v12.2.0按需增量静态重新生成 已稳定。
v12.1.0按需增量静态重新生成 已添加(测试版)。
v10.0.0添加了 localelocalesdefaultLocalenotFound 选项。
v10.0.0添加了 fallback: 'blocking' 返回选项。
v9.5.0稳定的增量静态重新生成
v9.3.0引入 getStaticProps