跳到主要内容

getStaticPaths

当从使用动态路由的页面导出一个名为 getStaticPaths 的函数时,Next.js 将静态预渲染由 getStaticPaths 指定的所有路径。

pages/repo/[name].tsx
import type {
InferGetStaticPropsType,
GetStaticProps,
GetStaticPaths,
} from 'next'

type Repo = {
name: string
stargazers_count: number
}

export const getStaticPaths = (async () => {
return {
paths: [
{
params: {
name: 'next.js',
},
}, // 请参阅下面的 "paths" 部分
],
fallback: true, // false 或 "blocking"
}
}) satisfies GetStaticPaths

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
}

getStaticPaths 返回值

getStaticPaths 函数应返回一个包含以下必需属性的对象:

paths

paths 键确定将预渲染哪些路径。例如,假设你有一个使用动态路由的页面,名为 pages/posts/[id].js。如果你从此页面导出 getStaticPaths 并为 paths 返回以下内容:

return {
paths: [
{ params: { id: '1' }},
{
params: { id: '2' },
// 配置了 i18n 后,也可以返回路径的区域设置
locale: "en",
},
],
fallback: ...
}

然后,Next.js 将在 next build 期间使用 pages/posts/[id].js 中的页面组件静态生成 /posts/1/posts/2

每个 params 对象的值必须与页面名称中使用的参数匹配:

  • 如果页面名称是 pages/posts/[postId]/[commentId],则 params 应包含 postIdcommentId
  • 如果页面名称使用捕获所有路由,如 pages/[...slug],则 params 应包含 slug(它是一个数组)。如果此数组是 ['hello', 'world'],则 Next.js 将在 /hello/world 静态生成页面。
  • 如果页面使用可选的捕获所有路由,使用 null[]undefinedfalse 来渲染最根部的路由。例如,如果你为 pages/[[...slug]] 提供 slug: false,Next.js 将静态生成页面 /

params 字符串区分大小写,理想情况下应进行规范化以确保正确生成路径。例如,如果为参数返回 WoRLD,则仅当实际访问的路径是 WoRLD 时才会匹配,而不是 worldWorld

配置了 i18n 时,除了 params 对象外,还可以返回 locale 字段,该字段配置正在生成的路径的区域设置。

fallback: false

如果 fallbackfalse,则 getStaticPaths 未返回的任何路径都将导致 404 页面

运行 next build 时,Next.js 将检查 getStaticPaths 是否返回了 fallback: false,然后它将构建由 getStaticPaths 返回的路径。如果你要创建的路径数量很少,或者新页面数据不经常添加,则此选项很有用。如果你发现需要添加更多路径,并且你有 fallback: false,则需要再次运行 next build 以生成新路径。

以下示例为名为 pages/posts/[id].js 的每个页面预渲染一篇博客文章。博客文章列表将从 CMS 获取并由 getStaticPaths 返回。然后,对于每个页面,它使用 getStaticProps 从 CMS 获取文章数据。

pages/posts/[id].js
function Post({ 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 },
}))

// 我们将仅在构建时预渲染这些路径。
// { fallback: false } 表示其他路由应该返回 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 } }
}

export default Post

fallback: true

示例

如果 fallbacktrue,则 getStaticProps 的行为将以下列方式改变:

  • getStaticPaths 返回的路径将在构建时由 getStaticProps 渲染为 HTML
  • 在构建时未生成的路径不会导致 404 页面。相反,Next.js 将在第一次请求此类路径时提供页面的"回退"版本。诸如 Google 之类的网络爬虫不会得到回退,而是路径将表现为 fallback: 'blocking'
  • 当通过 next/linknext/router(客户端)导航到 fallback: true 的页面时,Next.js _不会_提供回退,而是页面将表现为 fallback: 'blocking'
  • 在后台,Next.js 将静态生成请求的路径 HTMLJSON。这包括运行 getStaticProps
  • 完成后,浏览器接收生成路径的 JSON。这将用于使用所需的 props 自动渲染页面。从用户的角度来看,页面将从回退页面切换到完整页面。
  • 同时,Next.js 将此路径添加到预渲染页面列表中。对同一路径的后续请求将提供生成的页面,就像在构建时预渲染的其他页面一样。

提示:使用 output: 'export' 时不支持 fallback: true

何时 fallback: true 有用?

如果你的应用有大量依赖数据的静态页面(例如非常大的电子商务网站),fallback: true 很有用。如果你想预渲染所有产品页面,构建将需要很长时间。

相反,你可以静态生成一小部分页面,并对其余页面使用 fallback: true。当有人请求尚未生成的页面时,用户将看到带有加载指示器或骨架组件的页面。

不久之后,getStaticProps 完成,页面将使用请求的数据渲染。从现在开始,请求同一页面的每个人都将获得静态预渲染的页面。

这确保了用户始终拥有快速体验,同时保持快速构建和静态生成的好处。

fallback: true 不会_更新_生成的页面,为此请查看增量静态再生成

fallback: 'blocking'

如果 fallback'blocking'getStaticPaths 未返回的新路径将等待 HTML 生成,与 SSR 相同(因此称为 blocking),然后为将来的请求缓存,因此每个路径只发生一次。

getStaticProps 将表现如下:

  • getStaticPaths 返回的路径将在构建时由 getStaticProps 渲染为 HTML
  • 在构建时未生成的路径不会导致 404 页面。相反,Next.js 将在第一次请求时进行 SSR 并返回生成的 HTML
  • 完成后,浏览器接收生成路径的 HTML。从用户的角度来看,它将从"浏览器正在请求页面"过渡到"完整页面已加载"。没有加载/回退状态的闪烁。
  • 同时,Next.js 将此路径添加到预渲染页面列表中。对同一路径的后续请求将提供生成的页面,就像在构建时预渲染的其他页面一样。

fallback: 'blocking' 默认不会_更新_生成的页面。要更新生成的页面,请将增量静态再生成fallback: 'blocking' 结合使用。

提示:使用 output: 'export' 时不支持 fallback: 'blocking'

回退页面

在页面的"回退"版本中:

  • 页面的 props 将为空。
  • 使用路由器,你可以检测回退是否正在渲染,router.isFallback 将为 true

以下示例展示了使用 isFallback

pages/posts/[id].js
import { useRouter } from 'next/router'

function Post({ post }) {
const router = useRouter()

// 如果页面尚未生成,这将显示
// 直到 getStaticProps() 完成运行
if (router.isFallback) {
return <div>加载中...</div>
}

// 渲染文章...
}

// 此函数在构建时被调用
export async function getStaticPaths() {
return {
// 仅在构建时生成 `/posts/1` 和 `/posts/2`
paths: [{ params: { id: '1' } }, { params: { id: '2' } }],
// 启用静态生成其他页面
// 例如:`/posts/3`
fallback: true,
}
}

// 此函数也在构建时被调用
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 },
// 如果有请求进来,最多每秒重新生成一次文章
revalidate: 1,
}
}

export default Post

版本历史

版本变化
v13.4.0App 路由 现在稳定,数据获取更加简化,包括 generateStaticParams()
v12.2.0按需增量静态再生成 现已稳定。
v12.1.0添加了按需增量静态再生成(beta)。
v9.5.0稳定的增量静态再生成
v9.3.0引入 getStaticPaths