Next.jsの動的ルート(Dynamic Routes)の使い方

Next.jsでは、Dynamic Routes(動的ルート)を使用して、事前にURLセグメント名を決定せず、リクエスト時やビルド時に動的にルートを生成できます。この仕組みは、ブログ記事や商品ページのように動的なデータを扱う際に便利です。
【この記事で学べること】
- Dynamic Routesの基本と作成方法
- 動的セグメントで
params
を活用する方法 - 静的パラメータ生成(
generateStaticParams
)の仕組み - Catch-allセグメントとOptional Catch-allセグメントの使い方
1. Dynamic Routesの基本
Dynamic Segmentの作成
Dynamic Segmentは、フォルダ名を角括弧[]
で囲むことで作成します。
例: ブログ記事のルート
plaintextapp/ blog/ [slug]/ page.tsx
上記の構造では、[slug]
が動的セグメントとなり、/blog/:slug
形式のURLを扱えます。
コード例: 動的セグメントを使用
tsx// app/blog/[slug]/page.tsx export default function Page({ params, }: { params: { slug: string } }) { const slug = params.slug; return <div>My Post: {slug}</div>; }
動作例
Route | URL | params |
---|---|---|
/blog/[slug]/page.tsx | /blog/a | { slug: 'a' } |
/blog/[slug]/page.tsx | /blog/b | { slug: 'b' } |
2. 静的パラメータ生成(generateStaticParams
)
generateStaticParams
関数は、Next.jsのビルド時に動的なルートを静的に生成するための仕組みです。ブログ記事や製品詳細ページのように、コンテンツがデータベースやAPIで管理されている場合に便利です。
例: ブログ記事ページ: 例えば、ブログ記事をAPIから取得して、それぞれの記事に対応する静的なページを生成したい場合を考えます。
tsx// app/blog/[slug]/page.tsx export async function generateStaticParams() { const posts = await fetch('https://api.example.com/posts').then((res) => res.json() ); return posts.map((post) => ({ slug: post.slug, })); }
-
具体的な動作
-
APIから記事リストを取得: API(例:
https://api.example.com/posts
)にリクエストを送り、すべてのブログ記事のslug
を取得します。 -
ルートの生成:
slug
に基づき、以下の静的ルートがビルド時に生成されます。- /blog/post-1
- /blog/post-2
-
-
利点
- データ取得が自動的にメモ化され、ビルド時間が短縮されます。
- ビルド時に確定したルートを作成し、高速なパフォーマンスを実現。
3. Catch-allセグメント
Dynamic Routesは、...
を使って「Catch-allセグメント」を定義できます。これにより、複数のパスセグメントを1つの動的ルートでキャプチャできます。たとえば、カテゴリーやサブカテゴリーを持つECサイトで利用します。
ユースケース: ECサイトのカテゴリーページ
以下のフォルダ構造を持つサイトでは、/shop/a
や/shop/a/b
のような任意の深さのカテゴリーURLに対応できます。
plaintextapp/ shop/ [...slug]/ page.tsx
コード例
tsx// app/shop/[...slug]/page.tsx export default function CategoryPage({ params }: { params: { slug: string[] } }) { return ( <div> <h1>カテゴリ: {params.slug.join(' > ')}</h1> </div> ); }
動作例
Route | URL | params |
---|---|---|
/shop/[...slug]/page.tsx | /shop/a | { slug: ['a'] } |
/shop/[...slug]/page.tsx | /shop/a/b | { slug: ['a', 'b'] } |
4. Optional Catch-allセグメント
Optional Catch-allセグメント([[...slug]]
)は、URLのセグメントが存在しても、しなくても対応可能な柔軟なルート設定を提供します。
セグメントが空の場合(例: /shop
)でもページがマッチし、デフォルトの動作を実装できます。
なぜ使う?
Optional Catch-allセグメントは、複数のパス構造を1つのページで処理したい場合に役立ちます。これにより、ルート設定を簡略化しつつ、柔軟性を向上させます。
ユースケース1. ECサイトのカテゴリーページ
カテゴリーページでは以下のようなURL構造が一般的です:
/shop
→ すべての商品を表示(ショップのトップページ)。/shop/electronics
→ エレクトロニクスカテゴリの商品を表示。/shop/electronics/phones
→ サブカテゴリのスマートフォンを表示。
Optional Catch-allセグメントを使用すると、これらのURLに対して1つのコードで対応できます。
コード例: カテゴリーページの実装
tsx// app/shop/[[...slug]]/page.tsx export default function ShopPage({ params }: { params: { slug?: string[] } }) { const categoryPath = params.slug?.join(' > ') || '全商品'; return ( <div> <h1>ショップ: {categoryPath}</h1> <p>カテゴリに基づいた商品一覧を表示</p> </div> ); }
動作例
URL | params.slug | 表示内容 |
---|---|---|
/shop | undefined | ショップ: 全商品 |
/shop/electronics | ['electronics'] | ショップ: electronics |
/shop/electronics/phones | ['electronics', 'phones'] | ショップ: electronics > phones |
ユースケース2. 検索ページ
検索ページで以下のようなURL構造を考えます:
/search
→ 検索フォームを表示。/search/keyword
→ 特定のキーワードで検索結果を表示。/search/keyword1/keyword2
→ 複数のキーワードで検索結果を表示。
Optional Catch-allセグメントを使うと、キーワードがない場合(/search
)と複数キーワードの場合(/search/keyword1/keyword2
)を1つのコードで処理できます。
コード例: 検索ページの実装
tsx// app/search/[[...keywords]]/page.tsx export default function SearchPage({ params }: { params: { keywords?: string[] } }) { const searchQuery = params.keywords?.join(', ') || '指定なし'; return ( <div> <h1>検索結果: {searchQuery}</h1> <p>検索条件に基づいた結果を表示</p> </div> ); }
動作例
URL | params.keywords | 表示内容 |
---|---|---|
/search | undefined | 検索結果: 指定なし |
/search/nextjs | ['nextjs'] | 検索結果: nextjs |
/search/nextjs/react | ['nextjs', 'react'] | 検索結果: nextjs, react |
Optional Catch-allセグメントのまとめ
Optional Catch-allセグメントは、階層的なルートやデフォルト動作を持つアプリケーションで特に有効です。ECサイトや検索ページ、複数のセクションを持つページでの使用が推奨されます。
- 使う場面: トップページとサブページを一貫して処理する必要がある場合。
- メリット: 柔軟性と簡潔なルート管理。
これを理解することで、よりスケーラブルで保守性の高いアプリケーションを構築できます。
記事のまとめ
Dynamic Routesは、Next.jsで動的なデータを扱う際に不可欠な機能です。以下を押さえておきましょう:
- フォルダ名を角括弧
[]
で囲むことで動的セグメントを作成。 generateStaticParams
を使ってビルド時に静的ルートを生成。- Catch-allセグメントやOptional Catch-allセグメントで柔軟なルート設計が可能。
これらを活用することで、スケーラブルで効率的なアプリケーションを構築できます!