Skip to content
API ReferenceFunctionsgenerateStaticParams

generateStaticParams

generateStaticParams 函數可以與動態路由區段結合使用,以便在建置時靜態產生路由,而不是在請求時按需產生。

app/blog/[slug]/page.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 產生的動態區段時會發生什麼情況。
  • 您必須從 generateStaticParams 傳回空陣列,或使用 export const dynamic = 'force-static',才能重新驗證 (ISR) 執行階段的路徑
  • next dev 期間,當您導覽至路由時,將會呼叫 generateStaticParams
  • next build 期間,generateStaticParams 會在產生對應的版面配置或頁面之前執行。
  • 在重新驗證 (ISR) 期間,不會再次呼叫 generateStaticParams
  • generateStaticParams 取代了 Pages Router 中的 getStaticPaths 函數。

Parameters

options.params (選用)

如果路由中的多個動態區段使用 generateStaticParams,則子 generateStaticParams 函數會針對父函數產生的每個 params 集合執行一次。

params 物件包含從父 generateStaticParams 填入的 params,可用於在子區段中產生 params

Returns

generateStaticParams 應傳回物件陣列,其中每個物件代表單一路由的填入動態區段。

  • 物件中的每個屬性都是要為路由填入的動態區段。
  • 屬性名稱是區段的名稱,而屬性值應為該區段應填入的內容。
範例路由generateStaticParams 傳回類型
/product/[id]{ id: string }[]
/products/[category]/[product]{ category: string, product: string }[]
/products/[...slug]{ slug: string[] }[]

單一動態區段

app/product/[id]/page.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
  // ...
}

多個動態區段

app/products/[category]/[product]/page.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
  // ...
}

全部捕捉動態區段

app/product/[...slug]/page.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
  // ...
}

範例

靜態呈現

建置時的所有路徑

若要在建置時靜態呈現所有路徑,請將完整路徑清單提供給 generateStaticParams

app/blog/[slug]/page.tsx
export async function generateStaticParams() {
  const posts = await fetch('https://.../posts').then((res) => res.json())
 
  return posts.map((post) => ({
    slug: post.slug,
  }))
}

建置時的路徑子集

若要在建置時靜態呈現路徑的子集,並在第一次於執行階段存取時呈現其餘路徑,請傳回部分路徑清單

app/blog/[slug]/page.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 產生的動態區段時會發生什麼情況。

app/blog/[slug]/page.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,
  }))
}

執行階段的所有路徑

若要在第一次存取時靜態呈現所有路徑,請傳回空陣列 (在建置時不會呈現任何路徑) 或使用 export const dynamic = 'force-static'

app/blog/[slug]/page.js
export async function generateStaticParams() {
  return []
}

Good to know: 您必須一律從 generateStaticParams 傳回陣列,即使它是空的也一樣。否則,路由將會動態呈現。

app/changelog/[slug]/page.js
export const dynamic = 'force-static'

停用未指定路徑的呈現

若要防止未指定的路徑在執行階段靜態呈現,請在路由區段中新增 export const dynamicParams = false 選項。使用此配置選項時,只會提供 generateStaticParams 提供的路徑,而未指定的路由將會 404 或比對 (在全部捕捉路由的情況下)。

路由中的多個動態區段

您可以為目前版面配置或頁面上方的動態區段產生參數,但不能在下方。例如,假設路由為 app/products/[category]/[product]

  • app/products/[category]/[product]/page.js 可以為 [category][product] 兩者產生參數。
  • app/products/[category]/layout.js 只能[category] 產生參數。

有兩種方法可以為具有多個動態區段的路由產生參數

由下而上產生參數

從子路由區段產生多個動態區段。

app/products/[category]/[product]/page.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 }>
}) {
  // ...
}

由上而下產生參數

先產生父區段,然後使用結果來產生子區段。

app/products/[category]/layout.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 產生的每個區段執行一次。

generateStaticParams 函數可以使用從父 generateStaticParams 函數傳回的 params,以動態產生自己的區段。

app/products/[category]/[product]/page.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 }>
}) {
  // ...
}

Good to know: fetch 請求會自動針對跨所有 generate 首碼函數、版面配置、頁面和伺服器元件的相同資料進行記憶化。如果 fetch 無法使用,則可以使用 React cache

版本歷程記錄

版本變更
v13.0.0引入 generateStaticParams