0から知るReactでのRouterの話(2025/03/22改訂版)
2025/03/22更新: ルーターとは何か?という説明が抜けていましたので追記しました。初学者から見てもルーターとはがイメージしやすくなったと思います。
2025/3/19更新: 本記事内でApp RouterとTanStack Routerに関連して記載していた認証の実装例と解説については、ルーティングの話題とは別のトピックであり、正確性に欠ける部分があったため削除しました。認証の実装については、各フレームワークの公式ドキュメントを参照することをお勧めします。
はじめに
ルーターの選択肢は様々あり、どれを採用すべきか判断に迷うことが多くありました。プロジェクトの要件に最適なライブラリは何かといった判断ができたほうがいいと思いましたので、僕なりに調べてみて、ルーターとは何か?選択肢と特徴は何か?について学習した内容を記事にしています。
また表現として「ルーター」という場合は一般論の話、「Router」としている場合はパッケージや具体的なコードの話として使い分けます。
ツッコミ満載かもしれないのですが、あらましとしてこんなものがあってこうゆう考えがあって、んでこうゆうルーターがある、みたいなことがわかる程度にはまとまっていると思います。
フロントエンド開発におけるルーターとは?
フロントエンド開発においてルーターは、Webアプリケーション内での「ナビゲーション」(ユーザーがアプリケーション内の異なるページや画面間を移動すること)を管理する仕組みです。特にシングルページアプリケーション(SPA)では、ページ再読み込みなしでコンテンツを切り替えるために重要な役割を果たします。
ルーターの基本的な役割
ルーターの主な役割は以下の通りです:
- URL管理 - ブラウザのアドレスバーに表示されるURLと表示コンテンツを紐付けます
- コンポーネント切替 - URLに基づいて適切なコンポーネントを表示します
- 履歴管理 - ブラウザの戻る・進むボタンの動作を適切に制御します
- パラメータ処理 - URLパラメータやクエリパラメータを解析して活用します
ルーターが必要な理由
ルーターを使用する主な利点は以下の通りです:
- ユーザー体験の向上 - ページ全体の再読み込みなしでスムーズなコンテンツ切替を実現します
- 状態の保持 - ページ遷移時にアプリケーションの状態を維持できます
- ディープリンク対応 - アプリケーション内の特定画面への直接リンクが可能になります
- SEO対応 - 検索エンジンが個別コンテンツを認識できるようサポートします
一般的なフロントエンドルーターの機能
現代のルーターには次のような機能が実装されています:
- 宣言的なルート定義
- パラメータ付きの動的ルーティング
- ネストされたルート構造
- リダイレクト機能
- ルートガード(認証に基づくアクセス制御)
- コード分割との連携
これらの機能により、現代のWebアプリケーションはよりインタラクティブで使いやすいものになっています。
React Routerとは?
React Routerは、Reactアプリケーションでルーティングとナビゲーションを管理するライブラリです。URLとコンポーネントをマッピングすることで、シングルページアプリケーション(SPA)において、ページ全体を再読み込みせずにナビゲーションを実現します。これにより、以下の機能が提供されます:
- ディープリンクのサポート
- ブックマーク可能なURL
- ブラウザの履歴管理
React本体はルーティング機能を提供していません。React Routerのようなサードパーティライブラリを使用する必要があります。React Routerはコミュニティ主導で開発されており、事実上の標準ルーティングライブラリとして広く利用されています。
近年の重要な動向として、React Router v7からはRemixとの統合が完了しました。これはRemixの開発チームとReact Routerのチームが合流し、両者の技術を統合した成果です。この統合により、React Routerは単なるクライアントサイドルーターから、サーバーサイド機能を強化したフルスタックソリューションへと進化しています。
React Routerの主要コンポーネント
React Routerは環境に応じて異なるルーターコンポーネントを提供しています:
-
BrowserRouter: HTML5 History APIを使用し、クリーンなURLを実現(例:
/products
)- モダンなWebアプリケーションで一般的に使用
- サーバーが全てのURLをindex.htmlに向けるよう設定が必要
- 適したサイト: SEO重視の商用サイト、モダンなSPA、プログレッシブウェブアプリ(PWA)
-
HashRouter: URLのハッシュ部分を使用(例:
/#/products
)- サーバー側の設定変更が不要
- 古いブラウザとの互換性を持つ
- SEO面では不利
- 適したサイト: 静的ホスティング環境のアプリ、レガシーシステムの統合、SEOを重視しない社内ツール
-
MemoryRouter: メモリ上でURLの履歴を管理
- テスト環境やReact Nativeのような非ブラウザ環境で使用
- URLアドレスバーは更新されない
- 適したサイト: モバイルアプリ(React Native)、テスト環境、ウィジェット/埋め込みアプリ
-
StaticRouter: locationを変更しないルーター
- サーバーサイドレンダリング(SSR)用
- Nodeサーバー上でRenderに使用
- 適したサイト: SSRを実装したエンタープライズサイト、Node.jsバックエンドと連携したアプリ、SEO最適化が必要なコンテンツサイト
実装例(各タイプのRouter)
BrowserRouter
import { BrowserRouter, Routes, Route } from "react-router-dom";
function App() {
return (
<BrowserRouter>
<Routes>
<Route path="/" element={<Home />} />
<Route path="/products" element={<Products />} />
</Routes>
</BrowserRouter>
);
}
HashRouter
import { HashRouter, Routes, Route } from "react-router-dom";
function App() {
return (
<HashRouter>
<Routes>
<Route path="/" element={<Home />} />
<Route path="/products" element={<Products />} />
</Routes>
</HashRouter>
);
}
MemoryRouter
import { MemoryRouter, Routes, Route } from "react-router-dom";
function App() {
return (
<MemoryRouter initialEntries={["/products"]}>
<Routes>
<Route path="/" element={<Home />} />
<Route path="/products" element={<Products />} />
</Routes>
</MemoryRouter>
);
}
StaticRouter(サーバーサイドレンダリング用)
import { StaticRouter } from "react-router-dom/server";
import { Routes, Route } from "react-router-dom";
// サーバーサイドで使用
function ServerApp(req) {
return (
<StaticRouter location={req.url}>
<Routes>
<Route path="/" element={<Home />} />
<Route path="/products" element={<Products />} />
</Routes>
</StaticRouter>
);
}
フレームワークが提供しているRouter
フレームワークのRouterを選択すべき状況
React Routerのようなスタンドアロンのルーティングライブラリは柔軟性が高いですが、以下のような状況では、フレームワークに組み込まれたルーティングソリューションを選択するメリットがあります:
- SEOが重要な場合: React Router v7/Remixおよび Next.jsは、サーバーサイドレンダリング(SSR)やスタティックサイトジェネレーション(SSG)を標準サポートしています。
- 開発の高速化が必要な場合: ファイルベースのルーティングは規約に従った構造で直感的に開発できます。
- バックエンド連携が重要な場合: フレームワークはAPI連携の仕組みも一体化されていることが多いです。
- パフォーマンス最適化が重要な場合: 自動コード分割、プリフェッチなどの機能が組み込まれています。
- 大規模チーム開発の場合: 共通の規約と構造により、メンテナンス性が向上します。
React Router v7 (Remixと統合)
React Router v7は、Remixとの統合により、クライアントサイドルーティングだけでなく、サーバーサイド機能も強化されました。
特徴:
- Remixの強力なLoader/Actionパターンの統合
- サーバーサイドレンダリングのネイティブサポート
- エラーバウンダリの改善
- Web標準に基づくフォーム処理
ディレクトリ構造例
app/
├── root.tsx # アプリケーションのルートレイアウト
├── entry.client.tsx # クライアントエントリポイント
├── entry.server.tsx # サーバーエントリポイント
├── routes/
│ ├── _index.tsx # /(ホームページ)
│ ├── about.tsx # /about
│ ├── contact.tsx # /contact
│ ├── products.tsx # /products(商品一覧)
│ ├── products.$id.tsx # /products/123 など(動的パラメータ)
│ └── blog/
│ ├── _index.tsx # /blog
│ └── $slug.tsx # /blog/hello-world など
└── components/ # 共通コンポーネント
実装例
// app/routes/products.jsx
import { json } from "react-router-dom";
import { useLoaderData } from "react-router-dom";
export const loader = async () => {
// サーバーサイドでデータを取得
const products = await fetchProducts();
return json({ products });
};
export default function Products() {
const { products } = useLoaderData();
return (
<div>
<h1>商品一覧</h1>
<ul>
{products.map(product => (
<li key={product.id}>{product.name}</li>
))}
</ul>
</div>
);
}
Next.js App Router
Next.jsのApp Routerは、ファイルベースのルーティングを採用しています。app
ディレクトリ内のフォルダ構造が自動的にURLパスにマッピングされるため、直感的なルート管理が可能です。
特徴:
- Server Componentsによる部分ハイドレーション
- ストリーミングSSRサポート
ディレクトリ構造例
app/
├── page.tsx # / (ホームページ)
├── about/
│ └── page.tsx # /about
├── contact/
│ └── page.tsx # /contact
├── products/
│ ├── page.tsx # /products (商品一覧ページ)
│ └── [id]/ # 動的ルート [id]部分はパラメータ
│ └── page.tsx # /products/123 など
└── blog/
├── page.tsx # /blog
└── [slug]/
└── page.tsx # /blog/hello-world など
静的ルーティング
// app/about/page.tsx
export default function AboutPage() {
return <h1>会社概要ページ</h1>;
}
// app/contact/page.tsx
export default function ContactPage() {
return <h1>お問い合わせページ</h1>;
}
動的ルーティング
// app/products/[id]/page.tsx
export default function ProductPage({ params }: { params: { id: string } }) {
// 動的パラメータ `id` はpropsで受け取る
return <h1>商品ID: {params.id}</h1>;
}
TanStack Router
TanStack Routerは型安全性を最優先したクライアントルーターです。
特徴:
- JSON構造の検索パラメータ管理
- 自動プリフェッチ機能
- Zodスキーマによるパラメータ検証
-
.lazy
拡張子によるコード分割の自動化
ディレクトリ構造例
src/
├── main.tsx # エントリーポイント
├── App.tsx # ルートコンポーネント
├── routes/
│ ├── __root.tsx # ルート設定(レイアウト)
│ ├── index.tsx # / (ホームページ)
│ ├── about.tsx # /about
│ ├── contact.tsx # /contact
│ ├── dashboard.lazy.tsx # /dashboard (遅延ロード)
│ ├── products.tsx # /products (商品一覧)
│ └── products.$productId.tsx # /products/123 など
└── components/ # 共通コンポーネント
静的ルーティング
// src/routes/about.tsx
import { createFileRoute } from '@tanstack/react-router';
export const Route = createFileRoute('/about')({
component: () => <h1>会社概要</h1>
});
// src/routes/__root.tsx (ルート設定)
import { createRootRoute, Outlet } from '@tanstack/react-router';
export const Route = createRootRoute({
component: () => (
<div>
<nav>
<Link to="/">ホーム</Link>
<Link to="/about">会社概要</Link>
</nav>
<Outlet /> {/* 子ルートがここに表示される */}
</div>
)
});
.lazy
拡張子)
コード分割の自動化 (// src/routes/dashboard.lazy.tsx
import { createLazyFileRoute } from '@tanstack/react-router';
// `.lazy`拡張子を使用することで、このルートは必要になるまで
// 自動的にコード分割され、遅延ロードされる
export const Route = createLazyFileRoute('/dashboard')({
component: Dashboard,
});
// 大きなコンポーネントやライブラリをインポートしても
// 初期バンドルサイズには影響しない
function Dashboard() {
return (
<div>
<h1>ダッシュボード</h1>
<div className="dashboard-grid">
{/* 複雑なダッシュボードのコンポーネント */}
<DashboardStats />
<RecentActivity />
<PerformanceMetrics />
</div>
</div>
);
}
動的ルーティング (型安全)
// src/routes/products.$productId.tsx
import { createFileRoute } from '@tanstack/react-router';
import { z } from 'zod';
// 型安全なパラメータ検証
export const Route = createFileRoute('/products/$productId')({
// パラメータの検証 (TypeScript+Zodの型検証)
validateParams: (params) => {
return {
productId: z.string().parse(params.productId)
};
},
// 型安全なパラメータを使用するコンポーネント
component: ({ params }) => <h1>商品ID: {params.productId}</h1>
});
各Router比較表
特徴 | React Router v7 | Next.js App Router | TanStack Router |
---|---|---|---|
基本設計 | フルスタックフレームワーク | ハイブリッドSSR/SSG | 型安全重視のクライアントルーター |
ルーティング方式 | コード/ファイルベース | ファイルベース | ファイル/コードベース(型推論可能) |
型安全性 | 基本対応 | 基本対応 | 完全対応(TypeScript最適化) |
データ取得 | Loader/Action | Server Components + fetch | TanStack Query連携 |
ネストルーティング | ✅ | 🟡(レイアウト分離) | ✅(型安全なネスト構造) |
サーバーサイド機能 | ✅(Remix統合) | ✅(API Routes) | 🔶(アダプター経由で可能) |
検索パラメータ管理 | URLSearchParams | 文字列ベース | JSON構造 + スキーマ検証 |
プリフェッチ | ✅ | ✅(自動+手動) | ✅(自動最適化) |
エラーハンドリング | Error Boundary | error.js | エラー境界 + 型ガード |
開発者体験 | Web標準準拠 | ファイル構造重視 | 型補完 + Devtools統合 |
特徴的機能 | フォームアクション最適化 | インクリメンタル静的生成 | パスパラメータ検証 + ルート分割 |
凡例
✅ = 1st-classサポート、🟡 = 部分的なサポート、🔶 = カスタム実装が必要
特色・できること・できないこと・推奨用途
React Router v7
- 特色: Remixとの統合による強力なサーバーサイド機能とWeb標準準拠のフォーム処理
- できること: クライアント/サーバー両方でのデータ取得、フォームアクション処理、エッジ環境での実行
- できないこと: Next.jsのようなゼロコンフィグの静的生成
- 推奨用途: フォーム処理が多いアプリ、データ駆動型アプリケーション、既存のReact Routerプロジェクトのアップグレード
Next.js App Router
- 特色: インクリメンタル静的生成(ISR)
- できること: 動的ルートの静的生成、APIルート
- できないこと: 複雑なクライアントサイド状態管理、柔軟なルーティング設定
- 推奨用途: マーケティングサイト、ブログ
TanStack Router
- 特色: パスパラメータの自動型推論、組み込みキャッシュ
- できること: ルートベースのコード分割、型安全なURL管理
- できないこと: サーバーサイドレンダリング未対応、React Router v7のようなデータローディング
- 推奨用途: 型安全が必要な企業向けアプリ、複雑なUI構造のアプリ
フレームワーク選択の考え方
アプリケーションの種類による選択
-
単純なSPA(シングルページアプリケーション):
- React Router v7 がシンプルで十分な機能を提供
- Remixとの統合により、必要に応じてサーバー機能も利用可能
-
静的コンテンツサイト:
- Next.js の静的生成機能が最適解
- ビルド時に完全に静的な HTML を生成し、CDN でホスティング可能
- 画像最適化や Web Vitals 指標の向上に役立つ組み込み機能
- SEO 最適化が容易で、メタタグやソーシャルカード設定が直感的
- 小規模な静的サイトでは、Astro や Gatsby も選択肢として検討可能
-
静的サイト + 動的機能:
- Next.js App Router が静的生成と動的機能の組み合わせに優れている
- SEO対策とパフォーマンスの両立が重要な場合に最適
-
データ量の多い複雑なフォーム処理:
- React Router v7 のWeb標準に基づくフォーム処理が優れている
- エラー状態や読み込み状態の管理が必要な複雑なフォームに適している
-
企業向け大規模アプリケーション:
- TanStack Router の型安全性と拡張性が重要になる
- 開発者が多く、コードの品質管理が重要な場合に有効
チーム・開発者の視点からの選択
-
React初心者のチーム:
- React Router v7 のシンプルさが学習曲線を緩やかにする
- ドキュメントが充実しており、サンプルコードも豊富
-
フルスタック開発:
- React Router v7 または Next.js がフロントエンドとバックエンドの境界をシームレスにする
- APIエンドポイントとページを同一のコードベースで管理可能
-
TypeScript重視の開発環境:
- TanStack Router の完全な型安全性がコード品質と開発効率を向上
- コンパイル時のエラーチェックが強力
パフォーマンス要件
-
初期読み込み速度が重要:
- Next.js の静的生成(SSG)やインクリメンタル静的再生成(ISR)
- React Router v7 のプログレッシブエンハンスメントアプローチ
-
インタラクション応答性重視:
- React Router v7 または TanStack Router のクライアントサイドナビゲーション
- ページ遷移時のデータプリフェッチ機能
SEO要件
-
SEO最適化が必須:
- Next.js または React Router v7 のサーバーサイドレンダリング
- メタタグ管理や構造化データの実装が容易
-
SEOが重要でない内部アプリ:
- TanStack Router のシンプルなクライアントルーティング
デプロイ環境
-
静的ホスティング(Netlify/Vercel等):
- Next.js の静的出力オプション
- React Router v7 + 静的サイトジェネレーター
-
エッジコンピューティング:
- React Router v7 のアダプターシステム(Cloudflare Workersなど)
- Next.js のEdge Functions
-
従来型サーバー環境:
- 全てのソリューションが対応可能だが、React Router v7 と Next.js がSSR機能で優位
まとめ
選定基準 | 推奨Router | 強み | 弱み |
---|---|---|---|
型安全性 | TanStack Router | 完全な型推論、スキーマ検証 | サーバーサイドレンダリング未対応 |
SSG/ISR | Next.js App Router | 静的生成最適化 | クライアントサイド状態管理が複雑 |
フォーム処理 | React Router v7 | フォームアクション最適化、Web標準準拠 | フレームワーク外のツール連携が複雑 |
シンプルSPA | React Router v7 | 軽量実装、シンプルなAPI | Next.jsに比べて初期設定が必要 |
エッジデプロイ | React Router v7 | CDN最適化、サーバーレス実行 | 他のツールとの統合が必要な場合も |
RSC活用 | Next.js App Router | 部分ハイドレーション、サーバーコンポーネント | 学習コストが高い |
大規模アプリ | Next.js App Router | 大規模サイトでも最適化 | 初期セットアップが複雑 |
各ルーターには独自の強みと弱みがあるため、開発するアプリケーションの性質に最も適したものを選ぼうと思いました。
最近の重要な動向として、React RouterとRemixの統合(React Router v7)により、フルスタック開発の容易さが大幅に向上しています。この統合により、以前はRemixの強みだったサーバーサイド機能がReact Routerでも利用可能になり、既存のReact Routerプロジェクトでも簡単にサーバーサイド機能を追加できるようになりました。
また、TypeScriptを多用するプロジェクトではTanStack Routerの型安全性が大きなアドバンテージとなりますが、フルスタック機能を必要とするプロジェクトでは、React Router v7またはNext.jsの方が適している場合が多いようです。
Discussion
有益なまとめ記事ありがとうございます!
React Router v7
/Remix
はweb標準なのが魅力的ですよね。ところで、Next.js App Routerの以下部分が少し気になりました。
以下の記事で記載ありますように、認証チェックで DB 確認が必要な場合は
middleware.ts
では不十分なようです。上記記事の投稿時から技術進歩して、今は問題ないようになっているようでしたら確認不足で申し訳ありませんが参考になりますと幸いです。
コメントありがとうございます。
深い知見は僕も知りたいのでありがたいです。少し時間いただきますが確認したのち適宜修正します。
記事を修正・加筆しました。
認証についてはRouterのトピックとは違うためこの記事からは削除しました。
その代わり各種ルーターのサンプルを少し増やし、ディレクトリ構成もわかるようにして実装イメージを(僕が 笑)持ちやすいように変更しました。
@benjuwan さん
指摘ありがとうございました。コメントにあったリンク先の記事も読みましたが、個人情報流出させる脆弱性をあのままだと生み出してたかもです!助かりました!!