近年のフロントエンドでは、単一のブラウザアプリで動く SPA(Single Page Application)構成だけではなく、SSR(Server-Side Rendering)/ SSG(Static Generation)/ Server Components を組み合わせたハイブリッド構成が標準化しつつあります。
私のプロジェクトでも、当初は React Router v7 を使った典型的な SPA 構成からスタートしましたが、v7 の loader / action / resource route などを活用することで、実質的に SSR 挙動を持つアプリケーション構造として運用していました。
React Router v7 とは
React Router v7 は、いわゆる「ただのルーティングライブラリ」ではなく、フルスタック React フレームワークとしての機能を持つルーターです。
特徴としては以下のような点があります
dynamic routing/declarative routing を使った柔軟な URL 設定
loader / action / fetcher などによる サーバーサイドデータ取得やフォーム処理 を含むデータ駆動ルーティング機能
nested routes + <Outlet> によるレイアウト分離と UI の共通部分の明確な管理
「React による画面遷移 + データ取得 + レイアウト管理」を一貫して扱えるルーティング基盤、という立ち位置です。
React Router v7 で実現してきた SSR 構成は、Next.js App Router でより体系的に扱えるのではないかという考えが出てきたため、移行計画を整理し、記録としてまとめることにしました。
ルーティングモデルの根本思想
React Router v7(公式説明)
React Router は公式サイトで次のように説明されています:
“Dynamic routing for React”
出典:https://reactrouter.com/
React Router は ルーティングをコードで宣言し構築する仕組みです。
UIと遷移構造を React コンポーネントとして記述することが前提です。
例 routes.ts
ルーティング宣言の実例
React Router v7 では routes.ts のような場所に、以下のようにルート階層を宣言していきます:
// 顧客詳細
route(':id', 'routes/customers/customer.tsx', [
index('routes/customers/index.tsx'),
// 個人顧客詳細
route('individual', 'routes/customers/individual/individual.tsx', [
index('routes/customers/individual/index.tsx'),
// トップページ
route('top', 'routes/customers/individual/top/route.tsx')
])
// 法人顧客詳細
route('legalentity', 'routes/customers/individual/legalentity.tsx', [
index('routes/customers/legalentity/index.tsx'),
// トップページ
route('top', 'routes/customers/legalentity/top/route.tsx')
])
])
以下が上記ルートに対するディレクトリ構成
routes/
└── customers/
├── customer.tsx ← /customers/:id の親レイアウト・画面
├── index.tsx ← /customers/:id のインデックス画面
├── individual/
│ ├── individual.tsx ← /customers/:id/individual のルート
│ ├── index.tsx ← /customers/:id/individual のトップ
│ └── top/
│ └── route.tsx ← /customers/:id/individual/top
└── legalentity/
├── legalentity.tsx ← /customers/:id/legalentity のルート
├── index.tsx ← /customers/:id/legalentity のトップ
└── top/
└── route.tsx ← /customers/:id/legalentity/top
このように
1.route() で URL パターンを宣言
2.その URL に対応するコンポーネントファイルを紐づけ
3.children をネストすることで階層的な UI を構成
するスタイルが React Routerの基本設計です。
Next.js のような フォルダベースで route が自動認識される方式とは異なり、
React Router v7 ではアプリの遷移構造をコードとして宣言し、そこにデータ処理や UI やレイアウトを紐づけていくという設計哲学が採用されています。
Next.js App Router(公式説明)
Next.js の公式は次のように App Router を紹介しています:
“File-system based router built on Server Components.”
出典:https://nextjs.org/docs/app/building-your-application/routing
Next.js は ファイル構造によるルーティングと、
サーバーコンポーネントを中心にした設計を採用しています。
ルーティング宣言の実例(Next.js)
例えば、先ほどのReact Router v7で記述したルーティングは、Next.js App Router では、URL はフォルダ構造によって自動マッピングされます。
app/
└── customers/
└── [id]/
├── page.tsx ← /customers/:id の画面
│
├── individual/
│ ├── page.tsx ← /customers/:id/individual
│ └── top/
│ └── page.tsx ← /customers/:id/individual/top
│
└── legalentity/
├── page.tsx ← /customers/:id/legalentity
└── top/
└── page.tsx ← /customers/:id/legalentity/top
URL 対応するファイル
| URL | 対応するファイル |
|---|---|
/customers |
app/customers/page.tsx |
/customers/id |
app/customers/[id]/page.tsx |
/customers/id/individual |
app/customers/[id]/individual/page.tsx |
/customers/id/legalentity |
app/customers/[id]/legalentity/page.tsx |
/customers/id/individual/top |
app/customers/[id]/individual/top/page.tsx |
このように、React Router v7 のようにコードで route() を宣言するのではなく、
フォルダ/ファイルの配置=ルートの宣言
となるのが App Router の特徴です。
まとめ
React Router v7 は ルーティング・データ取得・レイアウト管理をコードで結びつける強力なフレームワーク的ルーターでした。
一方、Next.js App Router は 同じ概念をフォルダ構造と Server Components の仕組みによって標準化・体系化したアプローチと言えます。
“ルートをコードで記述するか、フォルダ構造で宣言するか”
という思想の違いはありますが、
両者は UI の構成・データ処理・ページ遷移を結びつけるという目的は共通しています。
結果として、
React Router で培った 「データ取得と UI 構造を結び付ける設計思考」は
App Router にそのまま適用できる
という点が今回の整理で見えてきました。
次回の記事では、API呼び出し編ということで
React Router v7のloader/actionを
Next.jsのServer Components/Server Actions機能
マッピングについて解説していきたいと思います。