@reach/router、react-router、react-router-dom、react-router-native は、すべて React アプリケーションにおける画面遷移と URL 管理を担うライブラリですが、役割と維持状況が異なります。react-router はプラットフォームに依存しないコアロジックを提供し、react-router-dom は Web ブラウザ環境向けの実装、react-router-native は React Native 向けの実装です。一方、@reach/router はかつてアクセシビリティを重視した軽量ルーターでしたが、現在は react-router v6 に統合され、公式に非推奨(deprecated)となっています。
React エコシステムにおいて、画面遷移と URL 管理はアプリケーションの構造を決定づける重要な要素です。react-router シリーズは業界標準として広く採用されていますが、パッケージが複数存在するため、初学者やアーキテクチャ選定時に混乱を招くことがあります。特に、かつて人気を博した @reach/router の扱いと、react-router コアと各プラットフォーム実装(DOM、Native)の関係性を正しく理解することが、堅牢なアプリケーション構築の第一歩です。
これら 4 つのパッケージは、同じ「ルーティング」という目的を持ちつつも、レイヤーと対象環境が明確に異なります。
react-router は「コア」です。
react-router-dom は「Web 向け実装」です。
react-router を同時にインストールするのが一般的です。react-router-native は「モバイル向け実装」です。
<a> タグなど)をネイティブコンポーネントに置き換えます。@reach/router は「過去の遺産」です。
react-router v6 へ吸収され、現在は非推奨です。パッケージごとに提供されるコンポーネントやフックには、環境に応じた違いがあります。特にルーターの初期化とリンクの扱いに注目します。
react-router-dom では、ブラウザの URL バーと同期する BrowserRouter を使用します。
// react-router-dom: Web 環境
import { BrowserRouter, Routes, Route, Link } from 'react-router-dom';
function App() {
return (
<BrowserRouter>
<nav><Link to="/about">About</Link></nav>
<Routes>
<Route path="/" element={<Home />} />
</Routes>
</BrowserRouter>
);
}
react-router-native では、ネイティブのスタックナビゲーションを模倣した NativeRouter を使用します。
// react-router-native: React Native 環境
import { NativeRouter, Routes, Route, Link } from 'react-router-native';
function App() {
return (
<NativeRouter>
<Link to="/about"><Text>About</Text></Link>
<Routes>
<Route path="/" element={<Home />} />
</Routes>
</NativeRouter>
);
}
react-router (コア) は、環境固有のラッパーなしでフックや低レベルコンポーネントを提供します。
// react-router: コアロジック(共通部分)
import { useNavigate, useParams } from 'react-router';
function UserProfile() {
const navigate = useNavigate();
const { id } = useParams();
// プラットフォームに依存しないナビゲーションロジック
return <button onClick={() => navigate(`/user/${id}`)}>View</button>;
}
@reach/router は、v6 以前の独自 API を使用していました(現在は使用非推奨)。
// @reach/router: 非推奨(レガシーコード例)
import { Router, Link } from '@reach/router';
// 現在の react-router-dom とは API が異なる
function App() {
return (
<Router>
<Link to="/about">About</Link>
{/* v6 以降の Routes/Route 構造とは異なる */}
</Router>
);
}
現代のルーティングでは、画面遷移に伴うデータ取得の扱いが重要です。react-router v6.4 以降では、データ API が強化されました。
react-router-dom では、loader を使ってルート遷移前にデータを取得できます。
// react-router-dom: Data API
import { createBrowserRouter, useLoaderData } from 'react-router-dom';
const router = createBrowserRouter([
{
path: "/user/:id",
element: <UserProfile />,
loader: async ({ params }) => {
return fetch(`/api/user/${params.id}`);
}
}
]);
function UserProfile() {
const data = useLoaderData(); // loader の結果を直接取得
return <div>{data.name}</div>;
}
react-router-native でも同様のデータパターンが利用可能ですが、ネットワーク層の扱いに注意が必要です。
// react-router-native: Data API
import { createStaticRouter, RouterProvider } from 'react-router-native';
// ネイティブ環境でも loader パターンは有効
const router = createStaticRouter([
{
path: "/user/:id",
loader: async ({ params }) => {
// ネイティブの fetch または API 呼び出し
return fetchMobileAPI(params.id);
}
}
]);
react-router コア自体はデータ取得ロジックを持ちませんが、これらの実装を支える基盤となります。
// react-router: コア
// データ取得自体は実装パッケージ(dom/native)に依存するが、
// 状態管理のコンテキストはここで定義されている
@reach/router には、標準のデータ取得パターン(loader など)は存在しませんでした。
// @reach/router: 標準のデータ取得機能なし
// useEffect 内で fetch を行う必要があり、コードが散乱しがちだった
function User({ id }) {
const [user, setUser] = useState(null);
useEffect(() => { fetchUser(id).then(setUser) }, [id]);
// ...
}
パッケージの選定において、メンテナンス状況は技術的負債に直結します。
@reach/router: 開発終了。セキュリティアップデートも期待できません。移行が必要です。react-router シリーズ: 活発にメンテナンスされています。v6 から v7 へ進化中で、TypeScript のサポートも強化されています。これら(@reach/router を除く現行バージョン)は、React の思想に深く根ざしています。
useNavigate、useLocation、useParams などのフックが共通して利用可能です。// どのパッケージでも共通のフック利用
import { useLocation } from 'react-router'; // or react-router-dom
function CurrentPath() {
const location = useLocation();
return <span>Current: {location.pathname}</span>;
}
// 宣言的ルート定義
<Routes>
<Route path="/home" element={<Home />} />
</Routes>
react-router シリーズは型定義が整備されています。// TypeScript での型推論
import { Link } from 'react-router-dom';
// to プロパティの型チェックが効く
<Link to="/about" />
| 特徴 | react-router-dom | react-router-native | react-router (Core) | @reach/router |
|---|---|---|---|---|
| 対象環境 | Web ブラウザ | React Native | 共通ロジック | Web (Legacy) |
| 主要コンポーネント | BrowserRouter, Link | NativeRouter, Link | Router, Routes | Router, Link |
| データ取得 | loader 対応 | loader 対応 | 非依存 | 非対応 |
| 保守状況 | ✅ アクティブ | ✅ アクティブ | ✅ アクティブ | ❌ 非推奨 |
| 推奨度 | ⭐⭐⭐⭐⭐ (Web) | ⭐⭐⭐⭐⭐ (Native) | ⭐⭐⭐⭐ (ライブラリ開発) | ⭐ (移行推奨) |
Web アプリケーションを構築する場合
迷わず react-router-dom を選択してください。これが事実上の標準です。react-router も同時にインストールされますが、直接インポートするのはフックなど共通機能に限られます。
React Native アプリを構築する場合
react-router-native を使用します。ただし、React Native 界隈では react-navigation も強力な競合であり、ネイティブ固有のジェスチャーやスタック管理を重視する場合は比較検討が必要です。
@reach/router を使っている場合
技術的負債を抱えている状態です。react-router-dom v6 への移行計画をすぐに立てるべきです。API の類似性が高いので、移行コストは比較的低く抑えられます。
ライブラリ開発者である場合
プラットフォームに依存しないルーティングロジックを実装したい場合のみ、react-router コアを直接参照します。ただし、多くの場合は各プラットフォーム向けにラッパーを提供することになります。
最終的に、現代の React 開発において「ルーティング=react-router シリーズ」という図式は変わっていません。重要なのは、その中で「どの環境向けのパッケージを選ぶか」を明確にすること、そして「過去の資産(@reach/router)に縛られないこと」です。
プラットフォーム固有の実装(DOM や Native)に依存しない共通のルーティングロジックやフック(useNavigate など)を共有したい場合に選択します。通常、単独ではなく react-router-dom や react-router-native の依存パッケージとして間接的に利用されます。
Web ブラウザ上で動作する React アプリケーション(SPA、SSR など)を構築する際の標準的な選択です。BrowserRouter や Link コンポーネントなど、Web 固有の機能が必要な場合は必ずこのパッケージを使用します。
新規プロジェクトでの使用は避けるべきです。このパッケージは開発が終了し、機能の多くが react-router v6 へ統合されました。既存のレガシーコードを維持する場合を除き、代わりに react-router-dom の採用を検討してください。
React Native を使用して iOS や Android のネイティブモバイルアプリを開発する場合に選択します。Web 固有の機能(history API など)の代わりに、ネイティブ環境に適したナビゲーションコンポーネントを提供します。
react-router is the primary package in the React Router project.
npm i react-router