📝
【React修行日記】動的ルーティングとパラメータ型
学習の目的
- React Router の useParams() フックを理解して使えるようにする
- TypeScript で useParams() の型を安全に扱う
- 一覧ページと詳細ページの動的ルーティングを実装できるようになる
React Router のルーティングと動的ルートの仕組み
ルート(=URLのパス)には大きく2つのタイプがある
| 種類 | 例 | 意味 |
|---|---|---|
| 静的ルート |
/about, /contact
|
固定ページ。誰が開いても同じ内容を表示する。 |
| 動的ルート(Dynamic Route) |
/users/:id, /products/:productId
|
パスの一部が変数のように変わるページ。 |
動的ルーティングの仕組み
React Routerでは、動的ルートは次のように設定する。
<Route path="/users/:id" element={<UserDetail />} />
:idの部分が動的パラメータとして扱われ、例えば/users/1と/users/2は同じコンポーネント(UserDetail)にアクセスするが、URLのidの値によって表示内容が切り替わる。
useParams()の概念
useParams()は、URLに含まれるパラメータを取得するReact Routerのフック。
URLパラメータはuseParams()で取得できる。
const { id } = useParams();
たとえばURLが/users/3のとき、idは"3"という文字列として取得される。
なぜ動的ルートが必要か?
動的ルーティングは、アプリで「ページの中身がデータ依存で変わる」個別ページを持つときに必要となる。
例:
| 機能 | URL例 | 備考 |
|---|---|---|
| ユーザプロフィール | /users/123 |
IDごとに内容が変わる |
| 商品詳細 | /products/999 |
同じテンプレートで別データを表示 |
| 記事詳細 | /articles/react-router-basics |
スラッグやIDで記事を特定 |
ユーザー一覧とユーザー詳細の実装
useParams()を使って、ユーザー一覧から動的に詳細ページへ遷移し、それぞれのユーザー情報を表示する仕組みを実装してみた...!

ダミーデータの準備
// src/data/users.ts
export type User = {
id: number;
name: string;
age: number;
};
export const users: User[] = [
{ id: 1, name: "Taro", age: 25 },
{ id: 2, name: "Hanako", age: 28 },
{ id: 3, name: "Jiro", age: 22 },
];
ルーティング設定
// src/App.tsx
import { Routes, Route } from "react-router-dom";
import UserList from "@/pages/UserList";
import UserDetail from "@/pages/UserDetail";
export default function App() {
return (
<Routes>
<Route path="/users" element={<UserList />} />
<Route path="/users/:id" element={<UserDetail />} />
<Route path="*" element={<h2>ページが見つかりません。</h2>} />
</Routes>
);
}
ポイント
-
/usersと/users/:idの関係
/usersはユーザー一覧ページ。
/users/:idは動的ルート(ユーザー詳細ページ)で、:idがURLパラメータとして扱われる。
→同じ「/users」階層でも、:idの有無で別ページにルーティングされる。 -
*(ワイルドカードルート)
どのルートにも一致しなかった場合に表示する「404ページ」。
ユーザー一覧ページ
import { users } from "@/data/users";
import { Link } from "react-router-dom";
export default function UserList() {
return (
<div>
<h2 className="text-2xl font-bold mb-6">ユーザー一覧</h2>
<ul className="space-y-3">
{users.map((user) => (
<li key={user.id}>
<Link
to={`/users/${user.id}`}
className="text-blue-600 hover:underline hover:text-blue-800"
>
{user.name}
</Link>
</li>
))}
</ul>
</div>
);
}
ユーザー詳細ページ
import { users } from "@/data/users";
import { Link, useParams } from "react-router-dom";
export default function UserDetail() {
// URLパラメータを取得
const { id } = useParams<{ id: string }>();
// IDに一致するユーザを検索
const user = users.find((u) => u.id === Number(id));
if (!user) {
return (
<div>
<h2>ユーザが見つかりません。</h2>
<Link to="/users">← 戻る</Link>
</div>
);
}
return (
<div className="flex flex-col items-center gap-6">
<h2 className="text-2xl font-bold">{user.name} のプロフィール</h2>
<div className="border-1 border-gray-600 p-2">
<p>ID:{user.id}</p>
<p>年齢:{user.age}</p>
</div>
<Link
to="/users"
className="text-blue-600 hover:underline hover:text-blue-800"
>
← 一覧に戻る
</Link>
</div>
);
}
ポイント
// URLパラメータを取得
const { id } = useParams<{ id: string }>();
// IDに一致するユーザを検索
const user = users.find((u) => u.id === Number(id));
-
useParams<{ id: string }>()
URLの/users/:idの「:id」部分を取得する。
TypeScriptの型パラメータ{ id: string }を指定することで、idが必ず存在し、文字列(string)として扱えるようになる。
(デフォルトではstring | undefinedなので、型を明示することで型安全にできる) -
Number(id)
useParams()で取得した値は 常に文字列(string) なので、usersのid(number型)と比較するために数値へ変換している。
まとめ
- URLの一部に
:idのような動的パラメータを設定することで、同じコンポーネントで複数のページを表示できる -
useParams()を使って、URLからパラメータを取得できる - TypeScriptで型パラメータを指定することで、型安全にパラメータを扱える
- この知識を使えば、一覧ページから詳細ページへの動的な遷移を安全に実装できる
参考
Discussion