概要
- Reactアプリケーションでページ遷移やルーティングを管理する React Router 6 の基本
-
createBrowserRouter
とRouterProvider
を用いた、現代的で型安全なルーティング構造 - 親子ルート構造(ネストルーティング) や エラーバウンダリ の基本的な使い方
React Router 6 によって 「URL に応じたコンポーネント描画、ページ遷移管理、エラーハンドリング」 がシンプルかつ型安全に実現できる
実施条件
- React + TypeScript プロジェクトが構築済みであること
- TypeScript での型定義の基本が理解できていること
- React コンポーネントの基本構造(関数コンポーネント、JSX)が理解できていること
環境
ツール | バージョン | 目的 |
---|---|---|
Node.js | 22.5.1 | Reactアプリ実行環境 |
React | 19.1.0 | UI構築 |
TypeScript | 4.9 | 型安全な開発 |
React Router | 6.14 | ルーティング管理 |
React Router 6 の基本構造
1. ディレクトリ構造例(基礎)
src/
├── routes/
│ ├── AppRouter.tsx # ルーター統合: React Router 6 のルート定義、ネストルート、エラーバウンダリを管理
│ ├── routeConfig.ts # ルート定義・型: URLパスの一元管理、型安全なルーティングを提供
│ └── index.ts # エクスポート管理: バルクエクスポート
├── pages/
│ ├── HomeScreen/
│ │ └── HomeScreen.tsx
│ ├── IntroScreen/
│ │ └── IntroScreen.tsx
│ ├── FeatureA/
│ │ └── FeatureA.tsx
│ ├── FeatureB/
│ │ └── FeatureB.tsx
│ ├── xxx/
│ │ └── xxx.tsx
│ └── NotFound/
│ └── NotFound.tsx
├── App.tsx # トップレベルコンポーネント: AppRouterを呼び出してアプリ全体の構造を提供
└── index.tsx # エントリーポイント: ReactDOM.createRootでApp.tsxをブラウザにマウント
- ネストルーティングに対応しやすい構造
- ルート設定・コンポーネント・エクスポートを分離
- 将来的に FeatureWrapper や Layout を追加しやすい
2. エントリーポイント(index.tsx
)
// 1. importセクション
import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App';
import './index.css';
// 2. 関数定義セクション
const root = ReactDOM.createRoot(
document.getElementById('root') as HTMLElement
);
// 3.4 返り値構築・ロジックセクション
root.render(
<React.StrictMode>
<App />
</React.StrictMode>
);
export {};
-
ReactDOM.createRoot
でルートコンテナを生成 -
<App />
に全ルーター構造を統合 -
StrictMode
により副作用のチェックや将来の互換性を向上
3. ルーター統合コンポーネント(App.tsx
)
// 1. importセクション
import React from 'react';
import { AppRouter } from './routes';
import './App.css';
// 2. 関数定義セクション
function App(): React.JSX.Element {
// 3.4 返り値構築・ロジックセクション
return (
<div className="App">
<AppRouter />
</div>
);
}
// 4. exportセクション
export default App;
export {};
- ルーターを
<AppRouter />
に集約 - 親レイアウトやネストルートの管理はここで行わず、専用コンポーネントに任せる
4. ルート設定と型(routeConfig.ts
)
// ===== 1. ルート定義セクション =====
/** ルート名(キー)の型とルートパス(値)の型 の両方を、リテラル型として固定したオブジェクト型 */
export const routeConfig = {
INTRO: '/',
HOME: '/home',
FEATURE_A: '/feature-a',
FEATURE_B: '/feature-b',
FEATURE_C: '/feature-c',
HISTORY: '/history',
SETTINGS: '/settings'
} as const;
// ===== 2. 型定義セクション =====
/** ルート名(キー)の型とルートパス(値)の型 */
export type RouteConfig = typeof routeConfig;
/** ルートパス(値)の型 */
export type RoutePath = RouteConfig[keyof RouteConfig];
// ===== 1. ルート定義セクション =====
/** フィーチャーID(キー)とルートパス(値)の両方を、リテラル型として固定したオブジェクト型 */
export const featureRouteMap = {
featureA: routeConfig.FEATURE_A,
featureB: routeConfig.FEATURE_B,
featureC: routeConfig.FEATURE_C,
history: routeConfig.HISTORY,
settings: routeConfig.SETTINGS,
} as const;
// ===== 2. 型定義セクション =====
/** フィーチャーID(キー)の型 */
export type FeatureId = keyof typeof featureRouteMap;
// ===== 3. 関数定義セクション =====
/** フィーチャーIDからルートパスを取得 */
export const getRouteByFeatureId = (featureId: string): RoutePath | null =>
featureRouteMap[featureId as FeatureId] || null;
/** ルートが実装済みかチェック */
export const isRouteImplemented = (route: RoutePath): boolean => {
const implementedRoutes: RoutePath[] = [
routeConfig.INTRO,
routeConfig.HOME,
routeConfig.FEATURE_A,
routeConfig.FEATURE_B,
routeConfig.FEATURE_C,
routeConfig.HISTORY,
routeConfig.SETTINGS
];
return implementedRoutes.includes(route);
};
- ルートパスを 一元管理 し、型安全に利用
-
FeatureId
とルートをマッピングし、未実装機能の判定にも利用可能
5. ルーター構成(AppRouter.tsx
)
// ===== 1. importセクション =====
import React from 'react';
import { createBrowserRouter, RouterProvider, Outlet, useRouteError, isRouteErrorResponse } from 'react-router-dom';
import { routeConfig } from './routeConfig';
import { HomeScreen } from '../pages/HomeScreen';
import { IntroScreen } from '../pages/IntroScreen';
import { FeatureA } from '../pages/FeatureA';
import { FeatureB } from '../pages/FeatureB';
import { FeatureC } from '../pages/FeatureC';
import { History } from '../pages/History';
import { Settings } from '../pages/Settings';
import { NotFound } from '../pages/NotFound';
// 未実装画面用のプレースホルダー
const ComingSoon: React.FC = () => <div>Coming Soon</div>;
// ===== 2. 関数定義セクション =====
// 2.1 エラーバウンダリコンポーネント
const RootErrorBoundary: React.FC = () => {
const error = useRouteError();
if (isRouteErrorResponse(error)) {
return (
<div>
<h1>{error.status} - {error.statusText}</h1>
{error.data?.message && <p>{error.data.message}</p>}
</div>
);
}
return <div>Something went wrong</div>;
};
// 2.2 レイアウトコンポーネント
const AppLayout: React.FC = () => (
<div className="app-layout">
<Outlet />
</div>
);
// 2.3 ルーター作成コンポーネント
export const AppRouter = () => {
const router = createBrowserRouter([
{
path: "/",
element: <AppLayout />,
errorElement: <RootErrorBoundary />,
children: [
{ path: routeConfig.INTRO, element: <IntroScreen />, index: true },
{ path: routeConfig.HOME, element: <HomeScreen /> },
{ path: routeConfig.FEATURE_A, element: <FeatureA /> },
{ path: routeConfig.FEATURE_B, element: <FeatureB /> },
{ path: routeConfig.FEATURE_C, element: <FeatureC /> },
{ path: routeConfig.HISTORY, element: <ComingSoon /> },
{ path: routeConfig.SETTINGS, element: <ComingSoon /> },
{ path: "*", element: <NotFound /> }
]
}
]);
// 3.4 返り値構築・ロジックセクション
return <RouterProvider router={router} />;
};
// 4. exportセクション
export default AppRouter;
- 親ルート
/
に AppLayout を配置 -
children
配列でページコンポーネントをネスト -
errorElement
でルートレベルのエラーを統合的にハンドリング
まとめ
- React Router 6 では
createBrowserRouter
とRouterProvider
が中心 - ルート定義を型安全に管理すると、開発効率と保守性が向上
- 親子ルート・エラーバウンダリ・未実装機能判定などを組み合わせることで 現代的で堅牢なルーティング が構築可能
参考リンク
- React Router 6 公式ドキュメント - 最新のAPIとベストプラクティス
- createBrowserRouter API - 新しいルーター作成方法
- データローダーパターン - ページレベルでのデータ取得最適化
- React Router 6 Tutorial - 公式の包括的なチュートリアル
- Error Handling - エラーバウンダリの実装方法
- React Router 6 Migration Guide - バージョン5からの移行ガイド
- TypeScript with React Router - TypeScript統合のベストプラクティス
- [React][TypeScript] Reactアプリの処理フロー完全解説 (npm start から描画まで)
- [React] React Router の超基礎