はじめに
React Routerの使い方や書き方を結構忘れていたのでまとめます。
調べていても、v6以前の書き方だったりして、最新の書き方が分かりにくかったので、最新の書き方をまとめます。
バージョン6以前とは書き方が大きく変わりますのでご注意ください。
動作環境
- React 19.2.8
- vite 8.3.0
- React Router 8.4.0
react-routerとreact-router-domの違い
本題に入る前の豆知識です。
Reactでルーティングを実装する時に利用するReact Routerですが、react-routerとreact-router-domが2種類あります。
- react-router:React Routerのコア機能
- react-router-dom:React Routerにブラウザ向けの機能を追加したパッケージ
react-router-domには<BrowserRouter>や<Link>などブラウザで使う機能が導入されていたため、Web開発では基本的にreact-router-domを使用するのが一般的でした。
React Router v7からreact-routerとreact-router-domの統合・統一がされてreact-routerからもreact-router-domの機能を使えるようになりました。
そのため、react-routerをインストールしてもreact-router-domの機能を利用できます。(v7以前のReact Routerではエラーになるので注意)
npm install react-router
当記事ではreact-routerを使用し、執筆時点の最新バージョンである8.4.0を利用しています。
基本設定
ルーティング設定をアプリ全体に適用する
アプリのエントリーポイントとなるコンポーネントに次のように書きます。
import { StrictMode } from 'react'
import { createRoot } from 'react-dom/client'
import { BrowserRouter } from 'react-router'
import App from './App.jsx'
createRoot(document.getElementById('root')).render(
<StrictMode>
<BrowserRouter>
<App />
</BrowserRouter>
</StrictMode>,
)
<BrowserRouter>で囲うことでルーティングの設定が有効化されます。
ルート設定をする
URLに割り当てるコンポーネントを設定します。
import { Routes, Route } from 'react-router';
import Home from './Home';
import Page1 from './Page1';
import Page2 from './Page2';
const App = () => {
return (
<Routes>
<Route index element={<Home />} />
<Route path='/page1' element={<Page1 />} />
<Route path='/page2' element={<Page2 />} />
</Routes>
);
}
export default App;
Routeに次のようにURLとコンポーネントを指定してURLとコンポーネントを紐づけます。
<Route path='URL' element={{/* コンポーネント */}} />
pathにURLを指定し、elementに表示するコンポーネントを指定します。pathではなくindexを指定するとトップページとして扱われます。
RouteはRoutesで囲まないと有効にならないので注意です。
画面遷移
ページ遷移をするためのリンクを設置します。
import { Link } from "react-router";
const Home = () => {
return (
<>
<h1>トップページです</h1>
<Link to="/page1">ページ1</Link>
<Link to="/page2">ページ2</Link>
</>
);
}
export default Home;
<Link>のtoにURLを指定することでリンクを設置できます。
<Link to='URL'>...</Link>
<Link>は<a>タグの代わりに使います。<a>タグを使うとページがリロードされてしまうので注意です。
ただ、<Link>は内部的にはaタグを使っているようなので、ブラウザの検証ツールから確認すると<a>タグとして表示されます。
そのため、target="_blank"などのaタグの属性を指定することも可能です。
<Link to='URL' target="blank">...</Link>
リンクを用いない画面遷移
リンククリック以外で画面遷移を行いたい場合はuseNavigateを使います。
import { useNavigate } from "react-router";
const Page1 = () => {
const navigate = useNavigate();
const onClickBack = () => navigate(-1);
return (
<>
<h1>Page1です</h1>
<button onClick={onClickBack}>前のページへ戻る</button>
</>
);
}
export default Page1;
useNavigateはReact Routerのフックで、画面遷移を行うための処理を行います。
navigateの引数にURLを指定することで画面遷移が可能です。数字を指定すると履歴の前後に遷移することもできます。
ログイン後やフォーム送信後に画面遷移を行う場合などに利用できます。
import { useNavigate } from 'react-router'
const LoginForm = () => {
const navigate = useNavigate();
const handleSubmit = () => {
// ログイン処理
navigate('/dashboard') // ログイン後にダッシュボードへ
}
return <button onClick={handleSubmit}>ログイン</button>
}
ネストされたページの画面遷移
次のようなネストされたページを設置する場合は、2パターンの書き方があります。
/page1
└── detailA
ネストされたページを設置するパターン1
import { Routes, Route } from 'react-router';
import Page1 from './Page1';
import Page1DetailA from './Page1DetailA';
const App = () => {
return (
<Routes>
<Route path='/page1' element={<Page1 />} />
<Route path='/page1/detailA' element={<Page1DetailA />} />
</Routes>
);
}
export default App;
<Route>のpathにネストされたURLを指定することでネストされたページを設置できます。
並列に<Route>を設置していくのでシンプルで分かりやすいですね。
こちらの書き方は、ネストされたページが少ない場合や、ネストの階層が浅い場合に向いています。
また後述する<Outlet>を使用せず、単純にURLごとに独立した画面を割り当てる場合に便利です。
ネストされたページを設置するパターン2
import { Routes, Route } from 'react-router';
import Page1 from './Page1';
import Page1DetailA from './Page1DetailA';
const App = () => {
return (
<Routes>
<Route path='/page1'>
<Route index element={<Page1 />} />
<Route path='detailA' element={<Page1DetailA />}>
</Route>
</Route>
</Routes>
);
}
export default App;
<Route path='/page1'>の中に<Route path='detailA'>を設置することで、URLの/page1を省略して書くことができます。
<Route index element={<Page1 />} />は/page1のトップページとして扱われます。その中に<Route path='detailA'>を設置することで、/page1/detailAのURLにアクセスした場合にPage1DetailAが表示されます。
さらに階層を深くする場合は次のように書きます。
import { Routes, Route } from 'react-router';
import Page1 from './Page1';
import Page1DetailA from './Page1DetailA';
import Page1DetailAItem01 from './Page1DetailAItem01'; // 追加
const App = () => {
return (
<Routes>
<Route path='/page1'>
<Route index element={<Page1 />} />
{/* 第2階層 */}
<Route path='detailA'>
<Route index element={<Page1DetailA />} />
{/* 第3階層 */}
<Route path='item01'>
<Route index element={<Page1DetailAItem01 />} />
</Route>
</Route>
</Route>
</Routes>
);
}
export default App;
こちらの書き方は、ネストされたページが多い場合や、ネストの階層が深い場合に向いています。
また次の<Outlet>を使用することで、共通レイアウトを設置できます。
import { Routes, Route } from 'react-router';
import Page1 from './Page1';
import Page1DetailA from './Page1DetailA';
import Page1Layout from './Page1Layout'; // 追加
const App = () => {
return (
<Routes>
<Route path='/page1' element={<Page1Layout />}>
<Route index element={<Page1 />} />
<Route path='detailA' element={<Page1DetailA />}>
</Route>
</Route>
</Routes>
);
}
export default App;
<Outlet>はReact Router v6から導入されたコンポーネントで、親コンポーネントの中に子コンポーネントを表示するための場所を指定できます。
<Route path='/page1' element={<Page1Layout />}>の中に書いた子コンポーネントは次の<Outlet />の位置に表示されます。
import { Outlet } from "react-router";
const Page1Layout = () => {
return (
<>
<header>Page1共通ヘッダー</header>
<main>
<Outlet /> // ここに子コンポーネントが表示される
</main>
<footer>Page1共通フッター</footer>
</>
);
};
export default Page1Layout;
<Outlet>を使用しない場合は親のルートにelementを省略した<Route path='/page1'>と書いてURLのグループ化として使用し、
<Outlet>を使用する場合は親のルートにelementを指定して親コンポーネントを共通レイアウトとして使用します。
URLパラメータの利用
商品ページやユーザーページなど、URLにIDを含めてページを表示する場合はURLパラメータを利用します。
import { Routes, Route } from 'react-router';
import UserProfile from './UserProfile';
const App = () => {
return (
<Routes>
<Route path='/profile/:id' element={<UserProfile />} />
</Routes>
);
}
export default App;
/profile/:idのように:をつけることでURLパラメータを指定できます。:以降の文字列はid以外も指定できます。/profile/1のようにアクセスすると、idの値が1として取得できます。
import { useParams } from "react-router";
const UserProfile = () => {
const { id } = useParams();
return <p>ようこそ!ユーザーID:{id}</p>
}
export default UserProfile;
URLパラメータを取得したい場合はuseParamsを使用します。useParamsはReact Routerのフックで、URLパラメータを取得するための処理を行います。
クエリパラメータの利用
サイト内検索などでURLのクエリパラメータを取得する場合はuseSearchParamsを使用します。
import { useSearchParams } from "react-router";
const Search = () => {
const [searchParams, setSearchParams] = useSearchParams();
return <p>検索キーワード:{searchParams.get("text")}</p>; // ?text=〇〇のURLクエリパラメータを取得できる
}
export default Search;
useSearchParamsはReact Routerのフックで、URLのクエリパラメータを取得するための処理を行います。別のフックであるuseLocationを使用してもクエリパラメータを取得できますが、useSearchParamsの方が簡単に取得でき、setSearchParamsを使用することでクエリパラメータの書き換えも可能です。
import { useSearchParams } from "react-router";
const Search = () => {
const [searchParams, setSearchParams] = useSearchParams();
const handleFilterChange = () => setSearchParams({ text: "hoge" });
return (
<>
<p>検索キーワード:{searchParams.get("text")}</p>
<button onClick={handleFilterChange}>条件変更</button>
</>
);
}
export default Search;
遷移先のページにデータを受け渡す
URLにパラメータを含めずに、遷移先のページにデータを受け渡す場合は<Link>のstateを使用します。
// stateにオブジェクトを指定するパターン
<Link to="/profile" state={{id: 1, name: "hoge"}}>プロフィール</Link>
<Link>のstateにオブジェクトを指定することで、遷移先のページにデータを受け渡すことができます。
<Link>のstateに指定したオブジェクトは、遷移先のページでuseLocationを使用することで取得できます。
import { useLocation } from "react-router";
const UserProfile = () => {
const location = useLocation();
const { id, name } = location.state || {};
return (
<>
<p>ユーザーID:{id}</p>
<p>ユーザーネーム:{name}</p>
</>
);
}
export default UserProfile;
注意点として、<Link>のstateに指定したオブジェクトは、ページのリロードやURLの直接入力で消えてしまいます。そのため、次のようにデータが存在しない場合の処理の追加をしておきましょう。
import { Link, useLocation } from "react-router";
const UserProfile = () => {
const location = useLocation();
const { id, name } = location.state || {};
// location.stateが存在しない場合の処理
if (!location.state) {
return (
<>
<p>データが取得できませんでした。</p>
<Link to="/">トップページへ戻る</Link>
</>
);
}
return (
<>
<p>ユーザーID:{id}</p>
<p>ユーザーネーム:{name}</p>
</>
);
}
export default UserProfile;
404ページを設置する
存在しないURLにアクセスした場合に表示する404ページを設置します。
import { Routes, Route } from 'react-router';
import NotFound from './NotFound';
const App = () => {
return (
<Routes>
<Route path='*' element={<NotFound />} />
</Routes>
);
}
export default App;
<Route path='*' element={<NotFound />} />のようにpathに*を指定することで、存在しないURLにアクセスした場合に表示する404ページを設置できます。
404ページのコンポーネントは次のような感じで良いと思います。
import { Link } from "react-router";
const NotFound = () => {
return (
<>
<p>ページが見つかりません。</p>
<Link to="/">トップページへ戻る</Link>
</>
);
}
export default NotFound;
なお404ページを設置する場合は、<Route path='*' element={<NotFound />} />は最後に書くようにしましょう。React Routerは上から順にルートを評価していくため、<Route path='*' element={<NotFound />} />が先に書かれていると、すべてのURLが404ページとして扱われてしまいます。
最後に
React Routerでよく使う機能をまとめました。React Router v6から書き方が大きく変わったので、調べる際のバージョンの確認は必ず行いましょう。
自分の体感ですがけっこうv6以前の書き方の情報が多いので、ドキュメントを確認するのが一番確実です。
参考
