主题
generateStaticParams
generateStaticParams 功能可以在构建时与 动态路由段 至 静态生成 路由结合使用,而不是在请求时按需使用。
¥The generateStaticParams function can be used in combination with dynamic route segments to statically generate routes at build time instead of on-demand at request time.
generateStaticParams 可用于:
¥generateStaticParams can be used with:
页面(
page.tsx/page.js)¥Pages (
page.tsx/page.js)布局(
layout.tsx/layout.js)¥Layouts (
layout.tsx/layout.js)路由处理程序(
route.ts/route.js)¥Route Handlers (
route.ts/route.js)
tsx
// Return a list of `params` to populate the [slug] dynamic segment
export async function generateStaticParams() {
const posts = await fetch('https://.../posts').then((res) => res.json())
return posts.map((post) => ({
slug: post.slug,
}))
}
// Multiple versions of this page will be statically generated
// using the `params` returned by `generateStaticParams`
export default async function Page({
params,
}: {
params: Promise<{ slug: string }>
}) {
const { slug } = await params
// ...
}需要了解:
¥Good to know:
你可以使用
dynamicParams段配置选项来控制当访问不是由generateStaticParams生成的动态段时会发生什么情况。¥You can use the
dynamicParamssegment config option to control what happens when a dynamic segment is visited that was not generated withgenerateStaticParams.你必须返回 来自
generateStaticParams的空数组 或利用export const dynamic = 'force-static'来重新验证 (ISR) 运行时的路径。¥You must return an empty array from
generateStaticParamsor utilizeexport const dynamic = 'force-static'in order to revalidate (ISR) paths at runtime.在
next dev期间,当你导航到某个路由时,将会调用generateStaticParams。¥During
next dev,generateStaticParamswill be called when you navigate to a route.在
next build期间,generateStaticParams在生成相应的布局或页面之前运行。¥During
next build,generateStaticParamsruns before the corresponding Layouts or Pages are generated.在重新验证 (ISR) 期间,不会再次调用
generateStaticParams。¥During revalidation (ISR),
generateStaticParamswill not be called again.
generateStaticParams取代了页面路由中的getStaticPaths功能。¥
generateStaticParamsreplaces thegetStaticPathsfunction in the Pages Router.
参数
¥Parameters
options.params(可选)
¥options.params (optional)
如果路由中的多个动态段使用 generateStaticParams,则对于父级生成的每组 params,子级 generateStaticParams 函数都会执行一次。
¥If multiple dynamic segments in a route use generateStaticParams, the child generateStaticParams function is executed once for each set of params the parent generates.
params 对象包含从父级 generateStaticParams 填充的 params,可用于 在子段中生成 params。
¥The params object contains the populated params from the parent generateStaticParams, which can be used to generate the params in a child segment.
返回
¥Returns
generateStaticParams 应返回一个对象数组,其中每个对象代表单个路由的填充动态段。
¥generateStaticParams should return an array of objects where each object represents the populated dynamic segments of a single route.
对象中的每个属性都是要为路由填充的动态段。
¥Each property in the object is a dynamic segment to be filled in for the route.
属性名称是段的名称,属性值是该段应填写的内容。
¥The properties name is the segment's name, and the properties value is what that segment should be filled in with.
| 示例路由 | generateStaticParams 返回类型 |
|---|---|
/product/[id] | { id: string }[] |
/products/[category]/[product] | { category: string, product: string }[] |
/products/[...slug] | { slug: string[] }[] |
单一动态段
¥Single Dynamic Segment
tsx
export function generateStaticParams() {
return [{ id: '1' }, { id: '2' }, { id: '3' }]
}
// Three versions of this page will be statically generated
// using the `params` returned by `generateStaticParams`
// - /product/1
// - /product/2
// - /product/3
export default async function Page({
params,
}: {
params: Promise<{ id: string }>
}) {
const { id } = await params
// ...
}多个动态片段
¥Multiple Dynamic Segments
tsx
export function generateStaticParams() {
return [
{ category: 'a', product: '1' },
{ category: 'b', product: '2' },
{ category: 'c', product: '3' },
]
}
// Three versions of this page will be statically generated
// using the `params` returned by `generateStaticParams`
// - /products/a/1
// - /products/b/2
// - /products/c/3
export default async function Page({
params,
}: {
params: Promise<{ category: string; product: string }>
}) {
const { category, product } = await params
// ...
}捕获所有动态片段
¥Catch-all Dynamic Segment
tsx
export function generateStaticParams() {
return [{ slug: ['a', '1'] }, { slug: ['b', '2'] }, { slug: ['c', '3'] }]
}
// Three versions of this page will be statically generated
// using the `params` returned by `generateStaticParams`
// - /product/a/1
// - /product/b/2
// - /product/c/3
export default async function Page({
params,
}: {
params: Promise<{ slug: string[] }>
}) {
const { slug } = await params
// ...
}示例
¥Examples
静态渲染
¥Static Rendering
构建时的所有路径
¥All paths at build time
要在构建时静态渲染所有路径,请向 generateStaticParams 提供完整的路径列表:
¥To statically render all paths at build time, supply the full list of paths to generateStaticParams:
tsx
export async function generateStaticParams() {
const posts = await fetch('https://.../posts').then((res) => res.json())
return posts.map((post) => ({
slug: post.slug,
}))
}构建时的路径子集
¥Subset of paths at build time
要在构建时静态渲染路径子集,并在运行时首次访问其余路径时返回部分路径列表:
¥To statically render a subset of paths at build time, and the rest the first time they're visited at runtime, return a partial list of paths:
tsx
export async function generateStaticParams() {
const posts = await fetch('https://.../posts').then((res) => res.json())
// Render the first 10 posts at build time
return posts.slice(0, 10).map((post) => ({
slug: post.slug,
}))
}然后,通过使用 dynamicParams 段配置选项,你可以控制当访问不是使用 generateStaticParams 生成的动态段时会发生什么情况。
¥Then, by using the dynamicParams segment config option, you can control what happens when a dynamic segment is visited that was not generated with generateStaticParams.
tsx
// All posts besides the top 10 will be a 404
export const dynamicParams = false
export async function generateStaticParams() {
const posts = await fetch('https://.../posts').then((res) => res.json())
const topPosts = posts.slice(0, 10)
return topPosts.map((post) => ({
slug: post.slug,
}))
}运行时的所有路径
¥All paths at runtime
要在第一次访问时静态渲染所有路径,请返回一个空数组(构建时不会渲染任何路径)或利用 export const dynamic = 'force-static':
¥To statically render all paths the first time they're visited, return an empty array (no paths will be rendered at build time) or utilize export const dynamic = 'force-static':
需要了解:
¥Good to know:
你必须始终从
generateStaticParams返回一个数组,即使它是空的。否则,将动态渲染路由。¥You must always return an array from
generateStaticParams, even if it's empty. Otherwise, the route will be dynamically rendered.
使用缓存组件
¥With Cache Components
将 缓存组件 与动态路由一起使用时,generateStaticParams 必须至少返回一个参数。空数组会导致 构建错误。这使得缓存组件能够在运行时验证你的路由是否会错误地访问 cookies()、headers() 或 searchParams。
¥When using Cache Components with dynamic routes, generateStaticParams must return at least one param. Empty arrays cause a build error. This allows Cache Components to validate your route doesn't incorrectly access cookies(), headers(), or searchParams at runtime.
需要了解:如果你在构建时不知道实际的参数值,可以返回一个占位符参数(例如
[{ slug: '__placeholder__' }])进行验证,然后在页面中使用notFound()处理它。但是,这会阻止构建时验证有效工作,并可能导致运行时错误。¥Good to know: If you don't know the actual param values at build time, you can return a placeholder param (e.g.,
[{ slug: '__placeholder__' }]) for validation, then handle it in your page withnotFound(). However, this prevents build time validation from working effectively and may cause runtime errors.
请参阅 动态路由部分 获取详细演练。
¥See the dynamic routes section for detailed walkthroughs.
使用路由处理器
¥With Route Handlers
你可以将 generateStaticParams 与 路由处理程序 结合使用,在构建时静态生成 API 响应:
¥You can use generateStaticParams with Route Handlers to statically generate API responses at build time:
ts
export async function generateStaticParams() {
return [{ id: '1' }, { id: '2' }, { id: '3' }]
}
export async function GET(
request: Request,
{ params }: RouteContext<'/api/posts/[id]'>
) {
const { id } = await params
// This will be statically generated for IDs 1, 2, and 3
return Response.json({ id, title: `Post ${id}` })
}路由带有缓存组件的处理程序
¥Route Handlers with Cache Components
使用 缓存组件 时,请结合 use cache 以获得最佳缓存效果:
¥When using Cache Components, combine with use cache for optimal caching:
ts
export async function generateStaticParams() {
return [{ id: '1' }, { id: '2' }, { id: '3' }]
}
async function getPost(id: Promise<string>) {
'use cache'
const resolvedId = await id
const response = await fetch(`https://api.example.com/posts/${resolvedId}`)
return response.json()
}
export async function GET(
request: Request,
{ params }: RouteContext<'/api/posts/[id]'>
) {
const post = await getPost(params.then((p) => p.id))
return Response.json(post)
}有关详细信息,请参阅 路由处理程序文档。
¥See the Route Handlers documentation for more details.
禁用未指定路径的渲染
¥Disable rendering for unspecified paths
要防止未指定的路径在运行时被静态渲染,请在路由段中添加 export const dynamicParams = false 选项。使用此配置选项时,仅提供 generateStaticParams 提供的路径,未指定的路由将 404 或匹配(在 包罗万象的路由 的情况下)。
¥To prevent unspecified paths from being statically rendered at runtime, add the export const dynamicParams = false option in a route segment. When this config option is used, only paths provided by generateStaticParams will be served, and unspecified routes will 404 or match (in the case of catch-all routes).
路由中的多个动态路段
¥Multiple Dynamic Segments in a Route
你可以为当前布局或页面上方的动态段生成参数,但不能在下方生成参数。例如,给定 app/products/[category]/[product] 路由:
¥You can generate params for dynamic segments above the current layout or page, but not below. For example, given the app/products/[category]/[product] route:
app/products/[category]/[product]/page.js可以为[category]和[product]生成参数。¥
app/products/[category]/[product]/page.jscan generate params for both[category]and[product].app/products/[category]/layout.js只能为[category]生成参数。¥
app/products/[category]/layout.jscan only generate params for[category].
有两种方法可以为具有多个动态段的路由生成参数:
¥There are two approaches to generating params for a route with multiple dynamic segments:
自下而上生成 params
¥Generate params from the bottom up
从子路由段生成多个动态段。
¥Generate multiple dynamic segments from the child route segment.
tsx
// Generate segments for both [category] and [product]
export async function generateStaticParams() {
const products = await fetch('https://.../products').then((res) => res.json())
return products.map((product) => ({
category: product.category.slug,
product: product.id,
}))
}
export default function Page({
params,
}: {
params: Promise<{ category: string; product: string }>
}) {
// ...
}从上到下生成参数
¥Generate params from the top down
首先生成父段,然后使用结果生成子段。
¥Generate the parent segments first and use the result to generate the child segments.
tsx
// Generate segments for [category]
export async function generateStaticParams() {
const products = await fetch('https://.../products').then((res) => res.json())
return products.map((product) => ({
category: product.category.slug,
}))
}
export default function Layout({
params,
}: {
params: Promise<{ category: string }>
}) {
// ...
}子路由段的 generateStaticParams 函数针对父路由 generateStaticParams 生成的每个段执行一次。
¥A child route segment's generateStaticParams function is executed once for each segment a parent generateStaticParams generates.
子 generateStaticParams 函数可以使用从父 generateStaticParams 函数返回的 params 来动态生成自己的段。
¥The child generateStaticParams function can use the params returned from the parent generateStaticParams function to dynamically generate its own segments.
tsx
// Generate segments for [product] using the `params` passed from
// the parent segment's `generateStaticParams` function
export async function generateStaticParams({
params: { category },
}: {
params: { category: string }
}) {
const products = await fetch(
`https://.../products?category=${category}`
).then((res) => res.json())
return products.map((product) => ({
product: product.id,
}))
}
export default function Page({
params,
}: {
params: Promise<{ category: string; product: string }>
}) {
// ...
}请注意,params 参数可以同步访问,并且仅包含父段参数。
¥Notice that the params argument can be accessed synchronously and includes only parent segment params.
对于类型补全,你可以将 TypeScript Awaited 助手与 Page Props helper 或 Layout Props helper 结合使用:
¥For type completion, you can make use of the TypeScript Awaited helper in combination with either Page Props helper or Layout Props helper:
ts
export async function generateStaticParams({
params: { category },
}: {
params: Awaited<LayoutProps<'/products/[category]'>['params']>
}) {
const products = await fetch(
`https://.../products?category=${category}`
).then((res) => res.json())
return products.map((product) => ({
product: product.id,
}))
}需要了解:对于所有
generate前缀的函数、布局、页面和服务器组件中的相同数据,fetch请求自动为 memoized。如果fetch不可用,则响应 可以使用cache。¥Good to know:
fetchrequests are automatically memoized for the same data across allgenerate-prefixed functions, Layouts, Pages, and Server Components. Reactcachecan be used iffetchis unavailable.
版本历史
¥Version History
| 版本 | 更改 |
|---|---|
v13.0.0 | generateStaticParams 已引入。 |