動的ルート
セグメント名を事前に正確に知らず、動的データからルートを作成したい場合、リクエスト時に埋められる、またはビルド時にプリレンダリングされる動的セグメントを使用できます。
規約
動的セグメントは、フォルダー名を角括弧で囲むことで作成できます:[folderName]
。例えば、[id]
や[slug]
などです。
動的セグメントは、layout
、page
、route
、generateMetadata
関数にparams
プロップとして渡されます。
例
例えば、ブログにはapp/blog/[slug]/page.js
のようなルートを含めることができ、[slug]
はブログ投稿の動的セグメントです。
export default async function Page({
params,
}: {
params: Promise<{ slug: string }>
}) {
const slug = (await params).slug
return <div>My Post: {slug}</div>
}
ルート | 例のURL | params |
---|---|---|
app/blog/[slug]/page.js | /blog/a | { slug: 'a' } |
app/blog/[slug]/page.js | /blog/b | { slug: 'b' } |
app/blog/[slug]/page.js | /blog/c | { slug: 'c' } |
セグメントのパラメータを生成する方法については、generateStaticParams()ページを参照してください。
補足
params
プロパティはプロミスであるため、値にアクセスするには async/await または React の use 関数を使用する必要があります。- バージョン14以前では、
params
は同期的なプロパティでした。後方互換性を確保するため、Next.js 15でも同期的にアクセスすることは可能ですが、この動作は将来的に非推奨となります。
- バージョン14以前では、
- 動的セグメントは
pages
ディレクトリの動的ルートと同等のものです。
静的パラメータの生成
generateStaticParams
関数は、動的ルートセグメントと組み合わせて使用し、リクエスト時にオンデマンドで生成するのではなく、ビルド時にルートを静的に生成できます。
export async function generateStaticParams() {
const posts = await fetch('https://.../posts').then((res) => res.json())
return posts.map((post) => ({
slug: post.slug,
}))
}
generateStaticParams
関数の主な利点は、データの賢明な取得です。generateStaticParams
関数内でfetch
リクエストを使用してコンテンツを取得する場合、リクエストは自動的にメモ化されます。これは、複数のgenerateStaticParams
、レイアウト、ページ間で同じ引数を持つfetch
リクエストが1回しか行われないことを意味し、ビルド時間を短縮します。
pages
ディレクトリから移行する場合は、移行ガイドを使用してください。
詳細情報と高度な使用例については、generateStaticParams
サーバー関数のドキュメントを参照してください。
キャッチオールセグメント
動的セグメントは、角括弧内に省略記号を追加することで、後続のセグメントをキャッチオールするように拡張できます:[...folderName]
。
例えば、app/shop/[...slug]/page.js
は/shop/clothes
にマッチするだけでなく、/shop/clothes/tops
、/shop/clothes/tops/t-shirts
などにもマッチします。
ルート | 例のURL | params |
---|---|---|
app/shop/[...slug]/page.js | /shop/a | { slug: ['a'] } |
app/shop/[...slug]/page.js | /shop/a/b | { slug: ['a', 'b'] } |
app/shop/[...slug]/page.js | /shop/a/b/c | { slug: ['a', 'b', 'c'] } |
オプションのキャッチオールセグメント
キャッチオールセグメントは、パラメータを二重の角括弧に含めることでオプションにできます:[[...folderName]]
。
例えば、app/shop/[[...slug]]/page.js
は、/shop/clothes
、/shop/clothes/tops
、/shop/clothes/tops/t-shirts
に加えて、/shop
にもマッチします。
キャッチオールとオプションのキャッチオールセグメントの違いは、オプションの場合、パラメータのないルート(上記の例では/shop
)もマッチする点です。
ルート | 例のURL | params |
---|---|---|
app/shop/[[...slug]]/page.js | /shop | { slug: undefined } |
app/shop/[[...slug]]/page.js | /shop/a | { slug: ['a'] } |
app/shop/[[...slug]]/page.js | /shop/a/b | { slug: ['a', 'b'] } |
app/shop/[[...slug]]/page.js | /shop/a/b/c | { slug: ['a', 'b', 'c'] } |
TypeScript
TypeScriptを使用する場合、設定されたルートセグメントに応じてparams
の型を追加できます。
export default async function Page({
params,
}: {
params: Promise<{ slug: string }>
}) {
return <h1>My Page</h1>
}
ルート | params の型定義 |
---|---|
app/blog/[slug]/page.js | { slug: string } |
app/shop/[...slug]/page.js | { slug: string[] } |
app/shop/[[...slug]]/page.js | { slug?: string[] } |
app/[categoryId]/[itemId]/page.js | { categoryId: string, itemId: string } |
補足: これは将来的に、TypeScriptプラグイン によって自動的に行われる可能性があります。