@reach/router、react-router-dom、react-router-native、wouter はすべて React 向けのルーティングライブラリですが、それぞれ異なる設計哲学と適用範囲を持っています。react-router-dom は Web 向けのフル機能ルーターとして広く使われており、react-router-native はその React Native 版です。wouter は軽量でシンプルな API を特徴とする代替選択肢です。一方、@reach/router は非推奨となっており、新規プロジェクトでの使用は推奨されません。これらのライブラリは、ルート定義、ナビゲーション、データ読み込み、プラットフォーム対応などの面で大きく異なります。
React アプリケーションでルーティングを実装する際、開発者は複数の選択肢に直面します。ここでは、@reach/router、react-router-dom、react-router-native、wouter の4つのパッケージについて、実際の開発観点から深く比較します。それぞれの設計思想、API の使い勝手、制限事項、そして現状のメンテナンス状況を踏まえ、プロジェクトに最適な選択を支援します。
まず重要な前提として、@reach/router は 公式に非推奨(deprecated) とされています。npm ページおよび GitHub リポジトリには明確に「このパッケージはメンテナンスされておらず、新規プロジェクトでの使用は推奨されない」と記載されています。代わりに react-router-dom v6 以降の使用が強く推奨されています。そのため、以下では歴史的文脈や移行の参考のために言及しますが、新規プロジェクトで @reach/router を選ぶべきではありません。
react-router-dom は、v6 以降で <Routes> と <Route> コンポーネントによる宣言的なルート定義を採用しています。パスパラメータは :id 形式で定義し、useParams() で取得します。
// react-router-dom
import { BrowserRouter, Routes, Route, useParams } from 'react-router-dom';
function User() {
const { id } = useParams();
return <div>User ID: {id}</div>;
}
function App() {
return (
<BrowserRouter>
<Routes>
<Route path="/users/:id" element={<User />} />
</Routes>
</BrowserRouter>
);
}
wouter は軽量かつシンプルな API を特徴とし、カスタムフック中心の設計です。ルート定義は <Route> コンポーネントではなく、useRoute() フックや <Switch> コンポーネントで行います。パスパラメータは配列分割で取得します。
// wouter
import { Switch, Route, useRoute } from 'wouter';
function User() {
const [match] = useRoute('/users/:id');
if (!match) return null;
return <div>User ID: {match.params.id}</div>;
}
function App() {
return (
<Switch>
<Route path="/users/:id" component={User} />
</Switch>
);
}
react-router-native は React Native 向けのルーティングライブラリで、react-router-dom とほぼ同じ API を提供しますが、ネイティブ環境向けに最適化されています。<NativeRouter> をルートプロバイダーとして使用します。
// react-router-native
import { NativeRouter, Routes, Route, useParams } from 'react-router-native';
function UserScreen() {
const { id } = useParams();
return <Text>User ID: {id}</Text>;
}
function App() {
return (
<NativeRouter>
<Routes>
<Route path="/users/:id" element={<UserScreen />} />
</Routes>
</NativeRouter>
);
}
@reach/router は JSX 内で直接パスを指定し、子要素としてコンポーネントを渡すスタイルでした。パスパラメータは props 経由で自動注入されました。
// @reach/router (非推奨)
import { Router, Link } from '@reach/router';
function User({ id }) {
return <div>User ID: {id}</div>;
}
function App() {
return (
<Router>
<User path="/users/:id" />
</Router>
);
}
<Link> コンポーネントを使用して、ブラウザ履歴を操作せずにナビゲーションを行います。プログラムによるナビゲーションには useNavigate() フックを使います。
import { Link, useNavigate } from 'react-router-dom';
function Nav() {
const navigate = useNavigate();
return (
<>
<Link to="/profile">Profile</Link>
<button onClick={() => navigate('/dashboard')}>Go to Dashboard</button>
</>
);
}
<Link> コンポーネントも提供しますが、より軽量な実装です。プログラムナビゲーションには useLocation() フックの setter を使います。
import { Link, useLocation } from 'wouter';
function Nav() {
const [, setLocation] = useLocation();
return (
<>
<Link href="/profile">Profile</Link>
<button onClick={() => setLocation('/dashboard')}>Go to Dashboard</button>
</>
);
}
<Link> は React Native の TouchableOpacity や Text と組み合わせて使用され、タッチ操作に対応します。
import { Link } from 'react-router-native';
import { TouchableOpacity, Text } from 'react-native';
function NavButton() {
return (
<Link to="/profile" component={TouchableOpacity}>
<Text>Profile</Text>
</Link>
);
}
react-router-dom: Web ブラウザ向け。HTML5 History API を利用。react-router-native: React Native 向け。ネイティブのナビゲーションスタックと連携。wouter: Web 専用。軽量でバンドルサイズを極力抑えたい Web アプリ向け。@reach/router: Web 専用だが、非推奨のため使用不可。重要なのは、Web と Native で同じルーティングロジックを共有したい場合でも、react-router-dom と react-router-native は別々のパッケージとしてインストール・使用する必要がある点です。共通のロジックはビジネスロジック層に分離し、ルート定義自体はプラットフォームごとに記述するのが一般的です。
v6 では、ルートのネストを <Route> の入れ子で表現できます。これにより、レイアウトコンポーネントとの組み合わせが容易になります。
<Routes>
<Route path="/dashboard" element={<DashboardLayout />}>
<Route index element={<Overview />} />
<Route path="settings" element={<Settings />} />
</Route>
</Routes>
ネストされたルートを直接サポートしていません。代わりに、複数の useRoute() を組み合わせるか、自前でロジックを実装する必要があります。
function Dashboard() {
const [match1] = useRoute('/dashboard/*');
const [match2] = useRoute('/dashboard/settings');
// 手動でマッチングを組み立てる必要あり
}
react-router-dom と同様にネストをサポートしますが、React Native の画面遷移パターン(スタック、タブなど)と組み合わせる際には注意が必要です。
react-router-dom v6.4 以降では、Loader と Action という新しいデータ読み込みパターンを導入しています。これにより、ルート単位で非同期データを安全に読み込むことが可能になりました。
// react-router-dom (v6.4+)
import { json } from 'react-router-dom';
const userLoader = async ({ params }) => {
const user = await fetchUser(params.id);
return json(user);
};
<Route path="/users/:id" loader={userLoader} element={<User />} />
一方、wouter や react-router-native にはこのような組み込みのデータ読み込み機構はありません。代わりに、useEffect やカスタムフック内でデータをフェッチする必要があります。
// wouter
function User() {
const [match] = useRoute('/users/:id');
const [user, setUser] = useState(null);
useEffect(() => {
if (match) {
fetchUser(match.params.id).then(setUser);
}
}, [match]);
return user ? <div>{user.name}</div> : <div>Loading...</div>;
}
react-router-dom: 大規模アプリケーション向けの豊富な機能(ネストルート、Loader/Action、エラーバウンダリ統合など)を提供。ただし、機能が多いため学習コストやバンドルサイズが増える可能性があります。wouter: 最小限の機能に絞り、バンドルサイズを極力小さく保つことを目的としています。高度なルーティング機能が必要ないシンプルなアプリに最適です。react-router-native: React Native 専用の抽象化を提供しますが、基本的なルーティング機能に留まります。複雑なナビゲーションには React Navigation と併用されることが多いです。| パッケージ | 推奨用途 | 注意点 |
|---|---|---|
react-router-dom | 中〜大規模な Web アプリ。SSR/SSG 対応、ネストルート、データ読み込み機構が必要な場合 | 機能が豊富な分、初期学習コストあり |
react-router-native | React Native アプリで、React Router の API に慣れているチーム | 複雑なネイティブナビゲーションには React Navigation が主流 |
wouter | 軽量さを重視する小規模 Web アプリやマイクロフロントエンド | ネストルートや高度な機能は自前実装が必要 |
@reach/router | 使用禁止 | 非推奨。既存コードは react-router-dom v6+ へ移行推奨 |
react-router-dom(v6.4+)を標準選択肢とし、必要に応じて wouter を検討。react-router-native よりも React Navigation を第一選択肢とすることが多いが、シンプルなユースケースや既存の React Router 知識を活かしたい場合は有効。react-router-dom v6 以降への移行を計画してください。ルーティングはアプリケーションの骨格となる部分です。プロジェクトの規模、チームのスキルセット、将来の拡張性を考慮して、慎重に選択しましょう。
react-router-dom は中〜大規模な Web アプリケーションに最適です。ネストされたルート、Loader/Action によるデータ読み込み、エラーハンドリング、SSR/SSG 対応など、本格的なアプリケーション開発に必要な機能が揃っています。チームが長期的に保守・拡張するプロジェクトでは、この安定したエコシステムを選ぶべきです。
バンドルサイズを極限まで削減したい小規模な Web アプリや、静的サイト、マイクロフロントエンドの一部として使う場合に適しています。API は最小限で直感的ですが、ネストルートや高度なデータ読み込み機構は提供されていません。シンプルさと軽量さを最優先するプロジェクトで選んでください。
このパッケージは公式に非推奨とされており、新規プロジェクトでの使用は絶対に避けてください。既存のコードベースがある場合は、react-router-dom v6 以降への移行を早急に計画すべきです。非推奨であるため、セキュリティ修正や新機能の追加は行われません。
React Native アプリで、かつ React Router の API にすでに慣れているチーム向けです。ただし、React Native の複雑なナビゲーション(タブ、スタック、モーダルなど)を実装するには、React Navigation の方がより適している場合が多いです。シンプルなルーティング要件で、Web 版とのコード共有を重視する場合に検討してください。
This package simply re-exports everything from react-router to smooth the upgrade path for v6 applications. Once upgraded you can change all of your imports and remove it from your dependencies:
-import { Routes } from "react-router-dom"
+import { Routes } from "react-router"