React Router
| 対応: | React 16.8(2019) |
|---|
『React Router』は、React アプリケーションにクライアントサイドルーティングを追加するためのライブラリです。URL のパスに応じてレンダリングするコンポーネントを切り替えることで、ページ遷移時にサーバーへのリクエストなしでビューを更新できます。
基本的な使い方(v6)
React Router v6 では BrowserRouter・Routes・Route の 3 つを組み合わせてルーティングを定義します。
// react-router-dom から必要なコンポーネントとフックをインポートします
import {
BrowserRouter,
Routes,
Route,
Link,
useParams,
useNavigate,
} from 'react-router-dom';
// ホームページコンポーネント
function Home() {
return <h1>ホームページ</h1>;
}
// 記事詳細ページコンポーネント
// URL パラメーター(:id)を useParams フックで取得します
function Article() {
const { id } = useParams();
return <h1>記事 ID: {id}</h1>;
}
// 存在しないパスに対応する 404 ページコンポーネント
function NotFound() {
return <h1>404 - ページが見つかりません</h1>;
}
// ナビゲーションコンポーネント
// Link はクリック時にページリロードなしで URL を切り替えます
function Nav() {
return (
<nav>
<Link to="/">ホーム</Link>
<Link to="/articles/1">記事 1</Link>
<Link to="/articles/2">記事 2</Link>
</nav>
);
}
// App コンポーネント(ルートコンポーネント)
// BrowserRouter でアプリ全体を囲み、ルーティングを有効にします
function App() {
return (
<BrowserRouter>
<Nav />
{/* Routes は子の Route を順番に評価し、最初にマッチしたものを描画します */}
<Routes>
{/* path="/" はホームページに対応します */}
<Route path="/" element={<Home />} />
{/* :id は URL パラメーターです。useParams() で取得できます */}
<Route path="/articles/:id" element={<Article />} />
{/* path="*" はどのパスにも一致しない場合のフォールバックです */}
<Route path="*" element={<NotFound />} />
</Routes>
</BrowserRouter>
);
}
export default App;
主なコンポーネント・フック一覧
| 名前 | 種別 | 概要 |
|---|---|---|
BrowserRouter | コンポーネント | HTML5 の History API を使ってルーティングを管理します。アプリ全体を囲むように配置します。 |
Routes | コンポーネント | 複数の Route をまとめ、現在の URL に最もマッチする 1 つだけを描画します。 |
Route | コンポーネント | path に指定したパターンと URL が一致したとき、element に渡したコンポーネントを描画します。 |
Link | コンポーネント | ページリロードなしで URL を切り替えるリンクを生成します。<a> の代わりに使います。 |
NavLink | コンポーネント | 現在の URL と一致するときに active クラスが自動付与される Link の拡張版です。 |
Navigate | コンポーネント | 描画時に指定した to へ即リダイレクトします。条件付きリダイレクトに使います。 |
Outlet | コンポーネント | ネストされたルートの子コンポーネントを描画するプレースホルダーです。 |
useParams() | フック | URL パラメーター(:id など)をオブジェクトとして返します。 |
useNavigate() | フック | プログラム的に URL を切り替える関数を返します。ボタンクリック後の遷移などに使います。 |
useLocation() | フック | 現在の URL のパス・クエリ文字列・ハッシュなどを含む location オブジェクトを返します。 |
useSearchParams() | フック | クエリ文字列(?key=value)を読み書きするための [searchParams, setSearchParams] を返します。 |
ネストされたルートと Outlet
親の Route の中に子の Route を入れ子にすることで、共通レイアウトを持つ複数ページを表現できます。子コンポーネントは親の Outlet の位置に描画されます。
import { BrowserRouter, Routes, Route, Outlet, Link } from 'react-router-dom';
// 共通レイアウトコンポーネント
// Outlet がネストされた子ルートの描画位置になります
function DashboardLayout() {
return (
<div>
<h1>ダッシュボード</h1>
<nav>
{/* 親ルートからの相対パスでリンクを指定します */}
<Link to="profile">プロフィール</Link>
<Link to="settings">設定</Link>
</nav>
{/* 子ルートのコンポーネントはここに描画されます */}
<Outlet />
</div>
);
}
function Profile() {
return <p>プロフィールページです。</p>;
}
function Settings() {
return <p>設定ページです。</p>;
}
function App() {
return (
<BrowserRouter>
<Routes>
{/* /dashboard 配下を DashboardLayout で包みます */}
<Route path="/dashboard" element={<DashboardLayout />}>
{/* /dashboard/profile → Profile を Outlet に描画します */}
<Route path="profile" element={<Profile />} />
{/* /dashboard/settings → Settings を Outlet に描画します */}
<Route path="settings" element={<Settings />} />
</Route>
</Routes>
</BrowserRouter>
);
}
export default App;
useNavigate によるプログラム遷移
フォーム送信後やボタンクリック後など、イベント処理の中でページを遷移させたい場合は useNavigate() フックを使います。
import { useNavigate } from 'react-router-dom';
function LoginForm() {
// navigate 関数を取得します
const navigate = useNavigate();
function handleSubmit(event) {
event.preventDefault();
// ログイン処理が成功したと仮定します
const success = true;
if (success) {
// 成功時はダッシュボードへ遷移します
navigate('/dashboard');
} else {
// 失敗時はエラーを表示するなどの処理を行います
alert('ログインに失敗しました。');
}
}
return (
<form onSubmit={handleSubmit}>
<button type="submit">ログイン</button>
</form>
);
}
export default LoginForm;
概要
React Router はシングルページアプリケーション(SPA)のルーティングにおいて事実上の標準ライブラリです。ブラウザの History API を活用することで、URL の変化に応じたコンポーネントの切り替えをページリロードなしに実現します。
v6 では Switch が廃止されて Routes に統一され、パスのマッチングが自動的に最も具体的なルートを優先する方式に変わりました。また、ネストされたルートと Outlet の組み合わせにより、共通レイアウトをシンプルに表現できます。
クエリ文字列の操作には useSearchParams()、現在の URL 情報の取得には useLocation() を使います。認証が必要なページへのアクセス制御は Navigate コンポーネントや useNavigate() を組み合わせて実装するのが一般的です。
関連ページ: lazy / Suspense / useContext
よくあるミス
BrowserRouter の外で Link を使ってエラーになる
<Link> や useNavigate などのコンポーネント・フックは、<BrowserRouter>(または <RouterProvider>)の子孫でないと動作しません。アプリ全体を BrowserRouter でラップする必要があります。
app_ng.jsx
import { Link } from 'react-router-dom';
// BrowserRouter でラップしていないためエラーになる
function App() {
return (
<div>
<Link to="/lab">ラボへ</Link>
</div>
);
}
修正後:
app_ok.jsx
import { BrowserRouter, Link } from 'react-router-dom';
function App() {
return (
<BrowserRouter>
<div>
<Link to="/lab">フューチャーガジェット研究所へ</Link>
</div>
</BrowserRouter>
);
}
useParams が undefined を返すケース
useParams で取得できるパラメータ名は <Route path="/member/:id"> のように : で宣言したものだけです。パスのパラメータ名とコード内の変数名が一致しないと undefined になります。また、Route の外で useParams を呼ぶと常に空オブジェクトが返ります。
params_ng.jsx
// Route に :memberId を定義しているのに id で取得しようとして undefined になる
<Route path="/member/:memberId" element={<MemberPage />} />
function MemberPage() {
const { id } = useParams(); // memberId ではなく id を取得しようとしている
return <p>メンバーID: {id}</p>; // undefined が表示される
}
修正後:
params_ok.jsx
function MemberPage() {
const { memberId } = useParams(); // Route のパラメータ名と一致させる
return <p>メンバーID: {memberId}</p>;
}
v5 の Switch を v6 で使おうとしてエラーになる
React Router v6 では <Switch> が廃止され、<Routes> に置き換えられました。v5 から v6 に移行する際は Switch を Routes に変更し、Route の書き方(component props → element props)も更新する必要があります。
記事の間違いや著作権の侵害等ございましたらお手数ですがこちらまでご連絡頂ければ幸いです。