Menu

generateStaticParams

generateStaticParams関数は、動的ルートセグメントと組み合わせて使用することで、リクエスト時にオンデマンドでレンダリングするのではなく、ビルド時に静的にルートを生成できます。

app/blog/[slug]/page.tsx
TypeScript
// [slug]動的セグメントを設定するための`params`のリストを返す
export async function generateStaticParams() {
  const posts = await fetch('https://.../posts').then((res) => res.json())
 
  return posts.map((post) => ({
    slug: post.slug,
  }))
}
 
// このページの複数のバージョンが、`generateStaticParams`から返される
// `params`を使用して静的に生成されます
export default async function Page({
  params,
}: {
  params: Promise<{ slug: string }>
}) {
  const { slug } = await params
  // ...
}

補足

  • 動的セグメント訪問時の動作を制御するには、dynamicParamsセグメント設定オプションを使用できます。
  • (ISR)で実行時にパスを再検証するには、generateStaticParamsから空の配列を返すか、export const dynamic = 'force-static'を使用する必要があります。
  • next dev実行中に、ルートへのナビゲーション時にgenerateStaticParamsが呼び出されます。
  • next build実行中に、generateStaticParamsは対応するレイアウトまたはページが生成される前に実行されます。
  • 再検証(ISR)中に、generateStaticParamsは再度呼び出されません。
  • generateStaticParamsは、Pages RouterのgetStaticPaths関数に置き換わります。

パラメータ

options.params(オプション)

ルート内で複数の動的セグメントがgenerateStaticParamsを使用する場合、親のgenerateStaticParamsが生成するparamsのセットごとに、子のgenerateStaticParams関数が1回実行されます。

paramsオブジェクトには、親のgenerateStaticParamsから設定されたparamsが含まれており、これを子セグメントでparamsを生成する際に使用できます。

戻り値

generateStaticParamsは、単一ルートの設定された動的セグメントを表すオブジェクトの配列を返す必要があります。

  • オブジェクト内の各プロパティは、ルートに設定される動的セグメントです。
  • プロパティ名はセグメント名で、プロパティ値はそのセグメントに設定される値です。
ルート例generateStaticParamsの戻り値
/product/[id]{ id: string }[]
/products/[category]/[product]{ category: string, product: string }[]
/products/[...slug]{ slug: string[] }[]

単一の動的セグメント

app/product/[id]/page.tsx
TypeScript
export function generateStaticParams() {
  return [{ id: '1' }, { id: '2' }, { id: '3' }]
}
 
// このページの3つのバージョンが、`generateStaticParams`から返される
// `params`を使用して静的に生成されます
// - /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
TypeScript
export function generateStaticParams() {
  return [
    { category: 'a', product: '1' },
    { category: 'b', product: '2' },
    { category: 'c', product: '3' },
  ]
}
 
// このページの3つのバージョンが、`generateStaticParams`から返される
// `params`を使用して静的に生成されます
// - /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
TypeScript
export function generateStaticParams() {
  return [{ slug: ['a', '1'] }, { slug: ['b', '2'] }, { slug: ['c', '3'] }]
}
 
// このページの3つのバージョンが、`generateStaticParams`から返される
// `params`を使用して静的に生成されます
// - /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
TypeScript
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
TypeScript
export async function generateStaticParams() {
  const posts = await fetch('https://.../posts').then((res) => res.json())
 
  // ビルド時に最初の10件の投稿をレンダリング
  return posts.slice(0, 10).map((post) => ({
    slug: post.slug,
  }))
}

その後、dynamicParamsセグメント設定オプションを使用することで、generateStaticParamsで生成されなかった動的セグメント訪問時の動作を制御できます。

app/blog/[slug]/page.tsx
TypeScript
// 上位10件以外のすべての投稿は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 []
}

補足generateStaticParamsから常に配列を返す必要があります。空の場合でも、返さないとルートは動的にレンダリングされます。

app/changelog/[slug]/page.js
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を生成する方法は2つあります:

ボトムアップでparamsを生成

子ルートセグメントから複数の動的セグメントを生成します。

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

トップダウンでparamsを生成

最初に親セグメントを生成し、その結果を使用して子セグメントを生成します。

app/products/[category]/layout.tsx
TypeScript
// [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が生成するセグメントごとに1回実行されます。

子のgenerateStaticParams関数は、親のgenerateStaticParams関数から返されたparamsを使用して、自身のセグメントを動的に生成できます。

app/products/[category]/[product]/page.tsx
TypeScript
// 親セグメントの`generateStaticParams`関数から渡された`params`を使用して
// [product]のセグメントを生成
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の引数は同期的にアクセスでき、親セグメントのparamsのみが含まれることに注意してください。

型補完の場合は、TypeScriptのAwaitedヘルパーとPage PropsヘルパーまたはLayout Propsヘルパーを組み合わせて使用できます:

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

補足fetchリクエストは自動的に、すべてのgenerate接頭辞の関数、レイアウト、ページ、およびサーバーコンポーネント全体で同じデータに対してメモ化されます。fetchが利用できない場合は、Reactcacheを使用できます。

バージョン履歴

バージョン変更内容
v13.0.0導入時期:generateStaticParams