← 解説「動的ルート — [id] でURLの一部を受け取る」に戻る
サンプルコードで身につける: 動的ルート — [id] でURLの一部を受け取る
解説で学んだ概念を、5つの具体例で確認します。素朴な例から実務寄りの例へと進みます。
1最小の [id] ページ
動的ルートの最小形で、URL の [id] 部分の実際の値を params から受け取って表示するだけの例です。params は Promise なので await で取り出す、という受け取り方の型もここで覚えてしまいましょう。
// app/items/[id]/page.tsx → /items/1 /items/2 ... すべてにマッチ
export default async function ItemPage({
params,
}: {
params: Promise<{ id: string }>;
}) {
const { id } = await params; // [id] 部分の実際の値
return <h1>アイテム {id} のページ</h1>;
}
// /items/1 なら id は "1"、/items/abc なら id は "abc"。
// 値は常に文字列として渡ってくる点に注意。
2ブログ記事の動的ルート
受け取った id でデータを探して表示する、動的ルートの定番の流れです。記事が何百件あってもファイルはこの1つだけで済む、という「同じレイアウトで中身だけ違うページ」の作り方そのものです。
// app/blog/[id]/page.tsx
const posts = [
{ id: "1", title: "はじめての投稿", body: "こんにちは。" },
{ id: "2", title: "Next.js 入門", body: "App Router を学ぶ。" },
];
export default async function PostPage({
params,
}: {
params: Promise<{ id: string }>;
}) {
const { id } = await params;
const post = posts.find((p) => p.id === id); // id で記事を探す
if (!post) {
return <p>記事が見つかりません</p>;
}
return (
<article>
<h1>{post.title}</h1>
<p>{post.body}</p>
</article>
);
}
31つのパターンが無数のURLを受け止める
app/blog/[id]/page.tsx という1ファイルがあらゆる /blog/◯◯ を処理する様子を、アクセスログの振り分けとして実行できる形にした例です。固定部分(blog)は一致が必要で、[id] 部分は何でも受け取る、という照合の感覚をつかめます。
TypeScript
4カテゴリと商品IDの2段の動的ルート
動的セグメントは1つの URL に複数置けることを示す例です。EC サイトの /products/カテゴリ/商品ID のような階層的な URL も、フォルダを2段にするだけで params にまとめて入ってきます。
// app/products/[category]/[id]/page.tsx
// → /products/books/123 や /products/games/9 にマッチ
export default async function ProductPage({
params,
}: {
params: Promise<{ category: string; id: string }>;
}) {
const { category, id } = await params;
return (
<main>
<p>カテゴリ: {category}</p>
<p>商品ID: {id}</p>
</main>
);
}
// /products/books/123 → category は "books"、id は "123"
5ユーザープロフィールページ
SNS の /users/ユーザー名 のように、ID 以外の文字列でも動的ルートが使える実務的な例です。一覧ページから各プロフィールへ Link でつなぐ構成は、記事・商品・ユーザーなどあらゆる「一覧と詳細」の原型になります。
// app/users/[username]/page.tsx → /users/kazu など
import Link from "next/link";
const users = [
{ username: "kazu", bio: "Web開発を勉強中" },
{ username: "mio", bio: "デザイナー" },
];
export default async function UserPage({
params,
}: {
params: Promise<{ username: string }>;
}) {
const { username } = await params;
const user = users.find((u) => u.username === username);
if (!user) return <p>ユーザーが見つかりません</p>;
return (
<main>
<h1>@{user.username}</h1>
<p>{user.bio}</p>
<Link href="/users">ユーザー一覧に戻る</Link>
</main>
);
}