メインコンテンツまでスキップ

generateStaticParams

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

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

Good to know:

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

パラメータ

options.params(オプション)

ルート内の複数の動的セグメントが 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
export function generateStaticParams() {
return [{ id: '1' }, { id: '2' }, { id: '3' }]
}

// `generateStaticParams` によって返された `params` を使用して
// このページの3つのバージョンが静的に生成されます
// - /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' },
]
}

// `generateStaticParams` によって返された `params` を使用して
// このページの3つのバージョンが静的に生成されます
// - /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 動的セグメント

app/product/[...slug]/page.tsx
export function generateStaticParams() {
return [{ slug: ['a', '1'] }, { slug: ['b', '2'] }, { slug: ['c', '3'] }]
}

// `generateStaticParams` によって返された `params` を使用して
// このページの3つのバージョンが静的に生成されます
// - /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())

// ビルド時に最初の10件の投稿をレンダリング
return posts.slice(0, 10).map((post) => ({
slug: post.slug,
}))
}

次に、dynamicParams セグメント設定オプションを使用して、generateStaticParams で生成されなかった動的セグメントが訪問されたときに何が起こるかを制御できます。

app/blog/[slug]/page.tsx
// 上位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 []
}

Good to know: generateStaticParams からは常に配列を返す必要があります。たとえそれが空であってもです。そうしないと、ルートは動的にレンダリングされます。

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

指定されていないパスのレンダリングを無効にする

指定されていないパスが実行時に静的にレンダリングされるのを防ぐには、ルートセグメントに export const dynamicParams = false オプションを追加します。この設定オプションが使用されると、generateStaticParams によって提供されたパスのみが提供され、指定されていないルートは404になるか(catch-all ルートの場合は)一致します。

ルート内の複数の動的セグメント

現在のレイアウトやページの上の動的セグメントのためにパラメータを生成できますが、下のセグメントのためには生成できません。たとえば、app/products/[category]/[product] ルートの場合:

  • app/products/[category]/[product]/page.js は、[category][product] の両方のパラメータを生成できます。
  • app/products/[category]/layout.js は、[category] のパラメータのみを生成できます。

複数の動的セグメントを持つルートのためにパラメータを生成するには、2つのアプローチがあります:

下から上にパラメータを生成する

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

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

上から下にパラメータを生成する

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

app/products/[category]/layout.tsx
// [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
// 親セグメントの `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 }>
}) {
// ...
}

Good to know: fetch リクエストは、すべての generate プレフィックス付き関数、レイアウト、ページ、サーバーコンポーネントで同じデータに対して自動的にメモ化されます。fetch が利用できない場合は、React cache を使用することができます

バージョン履歴

バージョン変更点
v13.0.0generateStaticParams が導入されました。