generateStaticParams
generateStaticParams
関数は、動的ルートセグメント と組み合わせて使用することで、リクエスト時にオンデマンドで生成する代わりに、ビルド時にルートを静的生成できます。
// [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
// ...
}
// [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 }) {
const { slug } = await params
// ...
}
知っておくと良いこと:
dynamicParams
セグメント設定オプションを使って、generateStaticParams
で生成されなかった動的セグメントにアクセスした時の挙動を制御できます。- ランタイムでパスを再検証 (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[] }[] |
単一の動的セグメント
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
// ...
}
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 }) {
const { id } = await params
// ...
}
複数の動的セグメント
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
// ...
}
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 }) {
const { category, product } = await params
// ...
}
キャッチオール動的セグメント
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
// ...
}
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 }) {
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())
// ビルド時に最初の10投稿をレンダリング
return posts.slice(0, 10).map((post) => ({
slug: post.slug,
}))
}
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
で生成されなかった動的セグメントにアクセスした時の挙動を制御できます。
// トップ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,
}))
}
// トップ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'
を使用します:
export async function generateStaticParams() {
return []
}
知っておくと良いこと:
generateStaticParams
からは常に配列を返す必要があります。空であってもです。そうでない場合、ルートは動的にレンダリングされます。
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]
のみのパラメータを生成できます。
複数の動的セグメントを持つルートのパラメータを生成するには2つの方法があります:
下から上に向けてパラメータを生成
子ルートセグメントから複数の動的セグメントを生成します。
// [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 }>
}) {
// ...
}
// [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 }) {
// ...
}
上から下に向けてパラメータを生成
まず親セグメントを生成し、その結果を使って子セグメントを生成します。
// [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 }>
}) {
// ...
}
// [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
が生成する各セグメントに対して1回ずつ実行されます。
子の generateStaticParams
関数は、親の generateStaticParams
関数から返された params
を使用して、自身のセグメントを動的に生成できます。
// 親セグメントの `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 }>
}) {
// ...
}
// 親セグメントの `generateStaticParams` 関数から渡された `params` を使って
// [product] セグメントを生成
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 }) {
// ...
}
知っておくと良いこと:
fetch
リクエストは、すべてのgenerate
プレフィックス付き関数、レイアウト、ページ、サーバーコンポーネント間で同じデータに対して自動的にメモ化されます。fetch
が利用できない場合は、React のcache
を使用できます。
バージョン履歴
バージョン | 変更内容 |
---|---|
v13.0.0 | generateStaticParams が導入されました。 |