generateStaticParams 函数可以与 动态路由段 结合使用,在构建时而不是在请求时按需 静态生成 路由。
// 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;
// ...
}// 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 }) {
const { slug } = await params;
// ...
}须知 (Good to know):
- 您可以使用
dynamicParams段配置选项,来控制当访问一个未使用generateStaticParams生成的动态段时会发生什么。- 您必须从
generateStaticParams返回一个空数组 或使用export const dynamic = 'force-static'来在运行时重新验证 (ISR) 路径。- 在
next dev期间,当您导航到一个路由时,generateStaticParams将会被调用。- 在
next build期间,generateStaticParams在生成相应的 Layouts 或 Pages 之前运行。- 在重新验证 (ISR) 期间,
generateStaticParams将不会再次被调用。generateStaticParams替换了 Pages Router 中的getStaticPaths函数。
options.params (可选)
如果路由中的多个动态段使用 generateStaticParams,则子级 generateStaticParams 函数将针对父级生成的每组 params 执行一次。
params 对象包含来自父级 generateStaticParams 中已填充的 params,这可用于在 子段中生成 params。
generateStaticParams 应返回一个对象数组,其中每个对象代表单个路由的已填充动态段。
| 示例路由 | generateStaticParams 返回类型 |
|---|---|
/product/[id] | { id: string }[] |
/products/[category]/[product] | { category: string, product: string }[] |
/products/[...slug] | { slug: string[] }[] |
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;
// ...
}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 }) {
const { id } = await params;
// ...
}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;
// ...
}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 }) {
const { category, product } = await params;
// ...
}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;
// ...
}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 }) {
const { slug } = await params;
// ...
}要在构建时静态渲染所有路径,请向 generateStaticParams 提供完整的路径列表:
export async function generateStaticParams() {
const posts = await fetch("https://.../posts").then((res) => res.json());
return posts.map((post) => ({
slug: post.slug,
}));
}export async function generateStaticParams() {
const posts = await fetch("https://.../posts").then((res) => res.json());
return posts.map((post) => ({
slug: post.slug,
}));
}要在构建时静态渲染一部分路径,而其余路径在运行时首次访问时渲染,请返回部分路径列表:
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,
}));
}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 生成的动态段时会发生什么。
// 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 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,
}));
}要在首次访问时静态渲染所有路径,请返回一个空数组(构建时不会渲染任何路径)或使用 export const dynamic = 'force-static':
export async function generateStaticParams() {
return [];
}须知 (Good to know): 您必须始终从
generateStaticParams返回一个数组,即使它是空的。否则,该路由将被动态渲染。
export const dynamic = "force-static";为了防止未指定的路径在运行时被静态渲染,请在路由段中添加 export const dynamicParams = false 选项。当使用此配置选项时,只有 generateStaticParams 提供的路径才会被提供,未指定的路由将返回 404 错误或匹配(在 全匹配路由 的情况下)。
您可以为当前布局或页面上方的动态段生成 params,但不能为下方的动态段生成。例如,给定 app/products/[category]/[product] 路由:
app/products/[category]/[product]/page.js 可以为 [category] 和 [product] 两者生成 params。app/products/[category]/layout.js 只能为 [category] 生成 params。有两种方法可以为具有多个动态段的路由生成 params:
params (Generate params from the bottom up)从子路由段生成多个动态段。
// 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 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 (Generate params from the top down)首先生成父段,并使用结果生成子段。
// 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 }>;
}) {
// ...
}// 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 }) {
// ...
}子路由段的 generateStaticParams 函数会为父级 generateStaticParams 生成的每组 params 执行一次。
子级 generateStaticParams 函数可以使用父级 generateStaticParams 函数返回的 params 来动态生成其自身的段。
// 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 }>;
}) {
// ...
}// Generate segments for [product] using the `params` passed from
// the parent segment's `generateStaticParams` function
export async function generateStaticParams({ params: { category } }) {
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 参数可以同步访问,并且只包含父段 params。
为了类型推断,您可以使用 TypeScript 的 Awaited 辅助类型,结合 Page Props 辅助类型 或 Layout Props 辅助类型 使用:
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,
}));
}须知 (Good to know): 对于所有
generate前缀函数、Layouts、Pages 和 Server Components 中相同数据的fetch请求会自动进行 记忆化。如果fetch不可用,可以使用 React 的cache。
| 版本号 | 变更 |
|---|---|
v13.0.0 | generateStaticParams 引入。 |