はい、承知いたしました。React Router DOMの最も基本的な紹介から使い方、そして実践的な例までを詳細に解説する、約5000語の記事を記述します。
いちばんやさしいReact Router DOM紹介と使い方:クライアントサイドルーティングの基本を徹底解説
はじめに:なぜReactアプリケーションにルーティングが必要なのか?
WebサイトやWebアプリケーションにおいて、「ルーティング」とは、ユーザーがアクセスしたURLに応じて、どのページ(またはコンポーネント)を表示するかを決定し、切り替える仕組みのことです。例えば、https://example.com/about
にアクセスしたら会社概要ページが表示され、https://example.com/products
にアクセスしたら商品一覧ページが表示される、といった挙動はルーティングによって実現されています。
従来のWebサイトでは、ユーザーが別のページへのリンクをクリックするたびに、ブラウザはサーバーに新しいページのHTMLファイルを要求し、受け取ったHTMLをレンダリングし直す、というプロセスを繰り返していました。これは「サーバーサイドルーティング」または「ページ遷移」と呼ばれるものです。
しかし、ReactのようなモダンなJavaScriptフレームワーク/ライブラリを使って開発されるアプリケーションの多くは、「Single Page Application (SPA)」と呼ばれるアーキテクチャを採用しています。SPAでは、最初に一度だけHTMLファイルと必要なJavaScript・CSSファイルを読み込んだ後、その後の画面の切り替えはJavaScriptが動的にDOM(Document Object Model)を操作して行います。ページ全体の再読み込みが発生しないため、ネイティブアプリケーションのようなスムーズで高速なユーザー体験を提供できるのが大きなメリットです。
SPAの利点は多い一方で、課題も存在します。それは、ブラウザのネイティブなページ遷移(URL変更とそれに伴うページ全体の再読み込み)を利用しないため、URLと表示されるコンテンツを同期させる仕組みを自分たちで作る必要がある、という点です。ユーザーがブラウザのアドレスバーに直接URLを入力してアクセスした場合、あるいは「戻る」「進む」ボタンをクリックした場合に、アプリケーションは現在のURLを正しく解釈し、対応する画面を表示しなければなりません。また、特定の画面へのリンクを他のユーザーと共有できるように、URLを意味のあるものにする(パーマリンク)必要もあります。
このSPAにおける「クライアントサイドルーティング」(ブラウザ側、つまりJavaScriptがURLに基づいて画面表示を切り替えること)を実現するための、Reactにおけるデファクトスタンダード(事実上の標準)ライブラリが、React Router DOM です。
この記事では、React Router DOMの最も基本的な使い方から、主要なコンポーネントの詳細、そして実践的な例までを、初心者の方でも理解できるように、コードを交えながら丁寧に解説していきます。この記事を最後まで読めば、React Router DOMを使って簡単なナビゲーションを持つSPAを構築できるようになるはずです。
対象読者:
- Reactの基本的な書き方は知っているが、ルーティングについては初めて学ぶ方
- React Router DOMの使い方をゼロから学びたい方
- Reactアプリケーションに複数のページや画面を作成したい方
この記事で学ぶこと:
- Reactアプリケーションにおけるルーティングの必要性
- React Router DOMとは何か
- React Router DOMのインストール方法
BrowserRouter
,Routes
,Route
,Link
といった主要なコンポーネントの使い方- URLパラメーターやクエリパラメーターの利用方法 (
useParams
,useSearchParams
) - プログラムによる画面遷移 (
useNavigate
) - ネストされたルート (Nested Routes) の基本的な考え方
- 404ページの実装方法
- NavLinkを使ったアクティブリンクのスタイリング
- よくある疑問とトラブルシューティング
さあ、React Router DOMの世界へ足を踏み入れましょう!
Reactアプリケーションにおけるルーティングの課題(もう少し詳しく)
SPAの最大の利点は、スムーズな画面遷移です。リンクをクリックしてもページ全体がリロードされないため、ユーザーはストレスなくアプリケーション内を移動できます。まるでネイティブアプリを使っているかのような体験です。
しかし、このスムーズさは、ブラウザが持つ本来の「ページ遷移」の仕組みを使わないことで実現されています。従来のウェブサイトでは、リンクをクリックするとブラウザが新しいHTMLファイルをサーバーに要求し、その新しいHTMLで画面全体を置き換えます。ブラウザのアドレスバーのURLも、要求したファイルのパスに合わせて変化します。
SPAでは、このHTMLファイルの要求・再読み込みを行いません。最初のページ読み込み時に、アプリケーションに必要なすべての(または多くの)JavaScriptコードがブラウザにダウンロードされます。その後の画面の切り替えは、ダウンロードされたJavaScriptコードが実行され、DOMの一部を書き換えることで行われます。
ここで問題になるのが、URLと表示されている画面の状態をどうやって同期させるか、です。
- URLのアドレスバーの表示: 画面が切り替わっても、アドレスバーのURLが変わらなければ、ユーザーは現在どの画面を見ているのか分かりません。また、そのURLをブックマークしたり、他の人に共有したりすることができません。
- ブラウザの「戻る」「進む」ボタン: ブラウザの「戻る」ボタンをクリックしたときに、アプリケーションは一つ前の画面状態に戻る必要があります。「進む」ボタンも同様です。ページ全体の再読み込みを伴わないSPAでは、この履歴管理を自分たちで行う必要があります。
- 直接アクセス: ユーザーがブラウザのアドレスバーに直接
/products/123
のようなURLを入力してエンターキーを押した場合、アプリケーションはURLの情報を読み取って、対応する商品ID 123の詳細画面を正しく表示する必要があります。
これらの課題を解決し、SPAでも従来のWebサイトと同じようにURLベースのナビゲーションを可能にするのが、クライアントサイドルーティングライブラリの役割です。React Router DOMは、Reactアプリケーションでこのクライアントサイドルーティングを実現するための、最も一般的で強力なライブラリです。
React Router DOMとは何か?
React Router DOMは、Reactアプリケーションに宣言的なクライアントサイドルーティングを提供する標準的なライブラリです。
「宣言的ルーティング」とは、どのようなパスに対してどのコンポーネントを表示したいかを、「〜ならば〜を表示する」という具体的な手順ではなく、「パス/about
が来たら About
コンポーネントを表示する」のように、目的や状態を宣言的に記述することで実現する考え方です。Reactのコンポーネント指向と非常に相性が良いです。React Router DOMは、ルーティングに関する設定を特別なファイルに記述するのではなく、Reactコンポーネントとして記述します。
react-router
と react-router-dom
の違い
React Routerは、ルーティングのコア機能を提供するライブラリです。これは、Webだけでなく、React Nativeなどの他のプラットフォームでも使用できる、プラットフォーム非依存の機能を含んでいます。
一方、React Router DOM は、react-router
のコア機能に加えて、Webブラウザ(DOM環境)でのルーティングに必要な機能(ブラウザの履歴APIとの連携、URLに基づいたナビゲーションなど)を追加したものです。Reactを使った通常のWebアプリケーション開発では、react-router-dom
をインストールして使用します。この記事でも react-router-dom
を扱います。
React Router DOMは、ブラウザの履歴API (pushState
, replaceState
など) を利用して、ページを再読み込みすることなくURLを変更し、履歴を管理します。そして、現在のURLに基づいて、どのReactコンポーネントをレンダリングすべきかを判断し、表示を切り替えます。
環境構築とインストール
React Router DOMを使うには、まずReactアプリケーションが必要です。まだReactアプリケーションを作成していない場合は、ViteまたはCreate React App (CRA) を使って新しいプロジェクトを作成しましょう。現在はViteを使うのが一般的で推奨されています。
Viteを使ったプロジェクト作成(推奨):
bash
npm create vite@latest my-react-app --template react
または
bash
yarn create vite my-react-app --template react
または
bash
pnpm create vite my-react-app --template react
プロジェクトフォルダ(my-react-app
)に移動し、依存関係をインストールします。
bash
cd my-react-app
npm install
または
bash
cd my-react-app
yarn install
または
bash
cd my-react-app
pnpm install
Create React Appを使ったプロジェクト作成(非推奨ですが、古いプロジェクトなどで使うこともあります):
bash
npx create-react-app my-react-app
または
bash
yarn create react-app my-react-app
プロジェクトフォルダ(my-react-app
)に移動します。
bash
cd my-react-app
React Router DOMのインストール
Reactプロジェクトの準備ができたら、次に react-router-dom
をインストールします。プロジェクトフォルダのルートで以下のコマンドを実行してください。
bash
npm install react-router-dom
または
bash
yarn add react-router-dom
または
bash
pnpm add react-router-dom
これで、あなたのReactプロジェクトでReact Router DOMを使う準備が整いました。
基本的な使い方:最小構成を知る
React Router DOMを使ったクライアントサイドルーティングは、いくつかの主要なコンポーネントを組み合わせて実現されます。まずは最も基本的な構成を見ていきましょう。
必要な主要コンポーネント:
BrowserRouter
: アプリケーション全体をラップし、ブラウザの履歴APIを使ってURLとUIを同期させます。React Router DOMを使うアプリケーションのルート(最上位)に配置する必要があります。Routes
: 複数のRoute
コンポーネントを囲むコンテナです。現在のURLにマッチする最初のRoute
を探し、その要素をレンダリングします。v6から導入されたコンポーネントで、以前のバージョンのSwitch
に相当しますが、より柔軟で効率的になっています。Route
: 特定のURLパスと、そのパスがマッチしたときに表示するコンポーネント(または要素)を紐付けます。path
プロパティでマッチさせるURLを指定し、element
プロパティでレンダリングするReact要素を指定します。Link
: クリックすると別のURLへナビゲートするためのコンポーネントです。ブラウザのページ遷移を使わずに、React Router DOMが内部でURLを変更し、対応するコンポーネントをレンダリングさせます。これはHTMLの<a>
タグに似ていますが、SPA内でのスムーズな遷移のために使われます。
では、これらのコンポーネントを使った簡単な例を見てみましょう。
まず、表示するいくつかのシンプルなコンポーネントを作成します。例えば、Home.js
, About.js
, Contact.js
の3つです。
“`javascript
// src/components/Home.js
import React from ‘react’;
function Home() {
return (
ホーム
ここはホーム画面です。
);
}
export default Home;
“`
“`javascript
// src/components/About.js
import React from ‘react’;
function About() {
return (
会社概要
このアプリケーションについての情報です。
);
}
export default About;
“`
“`javascript
// src/components/Contact.js
import React from ‘react’;
function Contact() {
return (
お問い合わせ
お問い合わせはこちらへ。
);
}
export default Contact;
“`
次に、これらのコンポーネントをルーティングで切り替えるように設定します。通常は、アプリケーションのルートコンポーネント(例: src/App.js
)や、ルーティングを設定したい特定の場所に記述します。
src/App.js
を以下のように変更します。
“`javascript
// src/App.js
import React from ‘react’;
import { BrowserRouter, Routes, Route, Link } from ‘react-router-dom’;
import Home from ‘./components/Home’;
import About from ‘./components/About’;
import Contact from ‘./components/Contact’;
function App() {
return (
// BrowserRouterでアプリケーション全体をラップする
<hr /> {/* 見た目の区切り線 */}
{/* Routesコンポーネントの中でRouteを定義する */}
{/* 現在のURLにマッチする最初のRouteがレンダリングされる */}
<Routes>
{/* path="/" にマッチしたら Home コンポーネントをレンダリング */}
<Route path="/" element={<Home />} />
{/* path="/about" にマッチしたら About コンポーネントをレンダリング */}
<Route path="/about" element={<About />} />
{/* path="/contact" にマッチしたら Contact コンポーネントをレンダリング */}
<Route path="/contact" element={<Contact />} />
</Routes>
</div>
</BrowserRouter>
);
}
export default App;
“`
このコードを説明します。
- まず、
react-router-dom
から必要なコンポーネント (BrowserRouter
,Routes
,Route
,Link
) をインポートしています。 - 作成した各ページコンポーネント (
Home
,About
,Contact
) もインポートします。 - アプリケーションのルートコンポーネントである
App
の中で、返すJSX全体を<BrowserRouter>
で囲んでいます。これはReact Router DOMを使う上での必須設定です。 <nav>
要素の中に、各ページへのナビゲーションリンクをリストとして作成しています。ここでHTML標準の<a href="...">
タグではなく、react-router-dom
からインポートした<Link to="...">
コンポーネントを使っているのがポイントです。Link
は、クリックしてもページ全体を再読み込みせず、SPA内でスムーズな画面遷移を実現します。to
プロパティに行き先のパスを指定します。- 次に
<Routes>
コンポーネントを配置しています。このRoutes
の中に、アプリケーションで扱うそれぞれのルート(パスとコンポーネントの対応関係)を定義します。 - それぞれのルートは
<Route>
コンポーネントとして定義します。path="/" element={<Home />}
は、「URLパスが/
(サイトのルート)にマッチしたら、<Home />
コンポーネントをレンダリングしてください」という意味です。path="/about" element={<About />}
は、「URLパスが/about
にマッチしたら、<About />
コンポーネントをレンダリングしてください」という意味です。path="/contact" element={<Contact />}
は、「URLパスが/contact
にマッチしたら、<Contact />
コンポーネントをレンダリングしてください」という意味です。element
プロパティには、パスがマッチしたときに実際にレンダリングしたいReact要素(通常はコンポーネント)を指定します。
この設定でアプリケーションを実行すると、画面上部に「ホーム」「会社概要」「お問い合わせ」というリンクが表示されます。これらのリンクをクリックすると、URLが /
、/about
、/contact
と変化し、それに応じて Routes
の中に定義された Route
が現在のURLにマッチするかを判定し、マッチした Route
の element
に指定されたコンポーネント (Home
, About
, Contact
) が <Routes>
の場所に表示されます。
これがReact Router DOMの最も基本的な使い方です。ブラウザのアドレスバーのURLと、表示されるコンテンツが連携して動くようになります。
主要コンポーネントの詳細解説
ここからは、先ほど登場した主要なコンポーネントについて、さらに詳しく見ていきましょう。
BrowserRouter
- 役割: アプリケーションのルートに配置し、ブラウザの履歴API (
history.pushState
,history.replaceState
) を使用してURLを管理し、React Router DOMがURLの変更を検知できるようにします。 - なぜ必要か: React Router DOMがブラウザのURL変更イベントを購読したり、プログラムでURLを変更したりするためには、この
BrowserRouter
のコンテキストが必要です。SPAでページ全体の再読み込みなしにURLを操作するために、ブラウザの履歴APIを使いますが、BrowserRouter
はそのAPIを抽象化し、React Router DOMの内部で使いやすくしてくれています。 -
使い方:
“`javascript
import { BrowserRouter } from ‘react-router-dom’;
import App from ‘./App’; // あなたのアプリケーションのルートコンポーネント// 通常は src/index.js (または src/main.jsx for Vite) でアプリケーション全体をラップします
const container = document.getElementById(‘root’);
const root = createRoot(container); // ReactDOMのcreateRootを使用 (React 18+)root.render(
{/ ここでBrowserRouterを使ってアプリケーション全体を囲む /}
);
``
src/index.js
多くの場合、アプリケーションのエントリーポイントファイル(例:や
src/main.jsx)で、ReactDOMの
renderまたは
createRoot().renderメソッドを使って、アプリケーションのルートコンポーネント(通常は
)をレンダリングする際に、その外側を
` でラップします。
Routes
- 役割: 複数の
<Route>
コンポーネントをグループ化するためのコンテナです。現在のURLと、子として含まれる各<Route>
のpath
を比較し、最初にマッチしたRoute
の要素(element
に指定したもの)をレンダリングします。 - なぜ必要か:
Routes
が存在することで、React Router DOMは複数のルート定義の中から、現在のURLに最適なルートを効率的に見つけ出すことができます。v6では、Routes
の中で定義された<Route>
は、最も具体的な(より長く正確な)パスから順にマッチングを試みるようになり、以前のバージョンのexact
プロパティが不要になりました。また、子ルートや相対パスの扱いもRoutes
を中心に行われます。 -
使い方:
“`javascript
import { Routes, Route } from ‘react-router-dom’;
// 各ページコンポーネントをインポートfunction App() {
return (
{/ … ナビゲーションなど … /}
{/ RouteコンポーネントをRoutesの中に配置 /}
} />
} />
{/ … 他のRoute … /}
{/ … フッターなど … /}
);
}
``
Routesの中に直接
コンポーネントを子として配置します。
Routesは現在のURLにマッチする **最初の** 子
Routeだけをレンダリングします(親ルートがマッチした場合は、その中の
Outlet` に子ルートがレンダリングされます。これはネストされたルートのセクションで詳しく説明します)。
Route
- 役割: 特定のURLパスと、表示するReact要素(通常はコンポーネント)を関連付けます。
- 主なプロパティ:
path
: マッチさせたいURLパスを指定します。静的なパス(例:/about
)だけでなく、動的なパスセグメント(例:/products/:productId
)やワイルドカード(例:*
)も指定できます。element
:path
が現在のURLにマッチしたときにレンダリングされるReact要素を指定します。<ComponentName />
の形式で記述するのが一般的です。v6から導入されたプロパティで、以前のバージョンのcomponent
やrender
の代わりに使われます。
-
使い方:
“`javascript
import { Routes, Route } from ‘react-router-dom’;
import Home from ‘./components/Home’;
import About from ‘./components/About’;
{/ パスが “/” にマッチしたらを表示 /}
} /> {/ パスが “/about” にマッチしたら
を表示 /}
} /> {/ 動的なパスセグメントを含むルート /}
} /> {/ マッチするルートがない場合のフォールバック (404ページなど) /}
} />
``
Routeコンポーネントは必ず
Routes` コンポーネントの子として配置する必要があります。 -
exact
プロパティについて (v6では不要に): 以前のバージョンのReact Routerでは、path="/" element={<Home />}
のようなルート定義で、/
だけでなく/about
や/contact
といった/
で始まるすべてのパスにHome
コンポーネントがマッチしてしまう問題を避けるために、exact
プロパティ (<Route exact path="/" ...>
) を使用する必要がありました。しかし、React Router v6のRoutes
コンポーネントは、自動的に最適な(最も具体的な)ルートを優先的にマッチさせるように設計されているため、基本的にexact
プロパティは不要になりました。path="/"
はルートパスのみにマッチし、/about
などにはマッチしません。
Link
- 役割: SPA内で別のURLへ遷移するためのナビゲーション要素を作成します。HTMLの
<a>
タグのように見えますが、クリックしてもブラウザのページ全体の再読み込みを行わず、React Router DOMが内部的にURLを変更し、対応するルートのコンポーネントをレンダリングさせます。 - 主なプロパティ:
to
: 遷移先のURLパスを指定します。文字列またはオブジェクトで指定できます。
-
使い方:
“`javascript
import { Link } from ‘react-router-dom’;``
* **タグとの違い:** HTMLの
タグは、クリックするとブラウザに新しいページを要求させ、ページ全体が再読み込みされます。SPAではこれを避けるため、
Linkコンポーネントを使用します。
Linkは内部的には
` タグをレンダリングしますが、クリックイベントを横取りしてデフォルトのブラウザの挙動(ページ再読み込み)を阻止し、React Router DOMの履歴APIを使ってURLを変更します。これにより、画面の一部だけが更新されるスムーズな遷移が実現されます。
実践的な例:簡単なナビゲーションバーの作成
先の基本的な使い方で見た App.js
のコードは、簡単なナビゲーションバーと、それに連動して表示が切り替わるコンテンツエリアの例として非常によくできています。
“`javascript
// src/App.js (再掲)
import React from ‘react’;
import { BrowserRouter, Routes, Route, Link } from ‘react-router-dom’;
import Home from ‘./components/Home’;
import About from ‘./components/About’;
import Contact from ‘./components/Contact’;
function App() {
return (
<hr />
{/* URLに応じたコンテンツ表示エリア */}
<Routes> {/* Route定義のコンテナ */}
<Route path="/" element={<Home />} /> {/* "/" にマッチしたら <Home /> を表示 */}
<Route path="/about" element={<About />} /> {/* "/about" にマッチしたら <About /> を表示 */}
<Route path="/contact" element={<Contact />} /> {/* "/contact" にマッチしたら <Contact /> を表示 */}
</Routes>
</div>
</BrowserRouter>
);
}
export default App;
“`
この構造は、多くのSPAの基本的なレイアウトパターンです。上部に常に表示されるナビゲーション(ヘッダーの一部として)、そしてその下にURLに応じて内容が切り替わるメインコンテンツエリアがあります。
<nav>
の中に置かれた <Link>
は、ユーザーがクリックするためのUI要素です。ユーザーが例えば「会社概要」リンクをクリックすると、ブラウザのアドレスバーのURLは /about
に変わりますが、ページ全体はリロードされません。
その下にある <Routes>
コンポーネントは、その時点でブラウザのアドレスバーに表示されているURL(この例では /about
)を見て、自身の子である <Route>
の path
と比較します。path="/about"
の <Route>
がマッチすると判断し、その element
に指定されている <About />
コンポーネントがレンダリングされ、<Routes>
コンポーネントがあった場所に表示されます。
このように、React Router DOMは、<Link>
によるURL変更をトリガーとして、<Routes>
が現在のURLに基づいて適切な <Route>
を探し、その element
をレンダリングするという流れで、画面の切り替えを実現します。
URLパラメーターの利用 (useParams
)
アプリケーションを開発していると、特定のアイテム(例: 商品、ユーザー、記事など)の詳細ページを表示したいことがよくあります。これらの詳細ページは、表示するアイテムによって内容が異なりますが、ページのデザインやレイアウトは共通していることが多いです。
例えば、商品詳細ページを表示する場合、URLを /products/1
や /products/2
のように、アイテムのIDを含めるのが一般的です。この 1
や 2
の部分は動的に変化します。React Router DOMでは、このような動的な部分を「URLパラメーター」として扱うことができます。
URLパラメーターを定義するには、<Route path>
の中に :パラメーター名
の形式で記述します。例えば、商品IDをパラメーターとして受け取る場合は path="/products/:productId"
のように定義します。
このパラメーターの値を、マッチしたルートでレンダリングされるコンポーネント内で取得するには、useParams
フックを使用します。useParams
は、URLに含まれるすべてのパラメーターをキーと値のペアとして持つオブジェクトを返します。
例を見てみましょう。商品詳細ページを表示するコンポーネント ProductDetail.js
を作成し、URLパラメーターから商品IDを取得して表示してみます。
まず、ProductDetail.js
コンポーネントを作成します。
“`javascript
// src/components/ProductDetail.js
import React from ‘react’;
import { useParams } from ‘react-router-dom’; // useParamsフックをインポート
function ProductDetail() {
// useParamsフックを使って、URLパラメーターを取得
// Routeのpathで定義した “:productId” というキーで値を取得できる
const { productId } = useParams();
// 実際にはここで取得したproductIdを使って、APIから商品データをフェッチするなどの処理を行う
return (
商品詳細
{/ 取得したproductIdを表示 /}
商品のID: {productId}
{/
ここに商品名や説明、画像などの詳細情報が表示されます。
/}
);
}
export default ProductDetail;
“`
次に、App.js
の <Routes>
の中に、この ProductDetail
コンポーネントに対応するルート定義を追加します。
“`javascript
// src/App.js (一部変更)
import React from ‘react’;
import { BrowserRouter, Routes, Route, Link } from ‘react-router-dom’;
import Home from ‘./components/Home’;
import About from ‘./components/About’;
import Contact from ‘./components/Contact’;
import ProductDetail from ‘./components/ProductDetail’; // ProductDetailをインポート
function App() {
return (
<hr />
<Routes>
<Route path="/" element={<Home />} />
<Route path="/about" element={<About />} />
<Route path="/contact" element={<Contact />} />
{/* 動的なパスセグメント ":productId" を含むルート */}
{/* 例: /products/123 や /products/abc にマッチする */}
<Route path="/products/:productId" element={<ProductDetail />} />
</Routes>
</div>
</BrowserRouter>
);
}
export default App;
“`
これで、/products/123
や /products/456
といったURLにアクセスすると、ProductDetail
コンポーネントがレンダリングされ、その中で useParams
フックを使って :productId
の部分の値 ("123"
や "456"
) を取得できるようになります。
useParams
フックの注意点:
useParams
は、コンポーネントが<Routes>
の中の<Route>
によって直接、またはネストされたルートの<Outlet>
を通じてレンダリングされた場合にのみ機能します。BrowserRouter
の直接の子など、ルート定義と関連付けられていない場所では使用できません。- 返されるパラメーターの値は常に文字列です。数値として扱いたい場合は、
parseInt()
などで変換する必要があります。
クエリパラメーターの利用 (useSearchParams
)
URLには、パスの他に「クエリパラメーター」という形で追加の情報を含めることがあります。クエリパラメーターは、URLの ?
の後に キー=値
の形式で記述され、複数の場合は &
で連結されます。例えば /products?category=electronics&sort=price
のような形式です。これらは主に、リストのフィルタリング、ソーティング、ページネーションなどの状態を保持するために使われます。
React Router DOM v6では、クエリパラメーターを扱うために useSearchParams
フックが提供されています。useSearchParams
フックは、URLのクエリ文字列を読み取ったり、更新したりするための機能を提供します。
useSearchParams
フックは、要素が2つの配列を返します。
- 現在のクエリパラメーターを表現する
URLSearchParams
オブジェクト。 - クエリパラメーターを更新するための関数。
例として、商品リストをカテゴリでフィルタリングする機能を考えてみましょう。
“`javascript
// src/components/ProductList.js
import React from ‘react’;
import { Link, useSearchParams } from ‘react-router-dom’; // useSearchParamsをインポート
function ProductList() {
// useSearchParamsフックを使って、[クエリパラメーターオブジェクト, 更新関数]を取得
const [searchParams, setSearchParams] = useSearchParams();
// 現在のカテゴリを取得 (URLが ?category=xxx なら ‘xxx’、なければ null)
const category = searchParams.get(‘category’);
// 表示する商品データのダミー(実際はAPIから取得)
const products = [
{ id: 1, name: ‘ノートパソコン’, category: ‘electronics’ },
{ id: 2, name: ‘本’, category: ‘books’ },
{ id: 3, name: ‘スマートフォン’, category: ‘electronics’ },
{ id: 4, name: ‘雑誌’, category: ‘books’ },
];
// 現在のカテゴリでフィルタリング
const filteredProducts = category
? products.filter(p => p.category === category)
: products; // categoryがなければ全て表示
// クエリパラメーターを更新する関数(例えば、フィルタボタンのクリックハンドラなど)
const handleFilterChange = (newCategory) => {
if (newCategory) {
// クエリパラメーターに category=newCategory を設定
setSearchParams({ category: newCategory });
} else {
// クエリパラメーターをクリア
setSearchParams({});
}
};
return (
商品リスト
{/* フィルタリングボタン */}
<div>
<button onClick={() => handleFilterChange(null)}>全カテゴリ</button>
<button onClick={() => handleFilterChange('electronics')}>電化製品</button>
<button onClick={() => handleFilterChange('books')}>書籍</button>
</div>
{/* 商品一覧 */}
<ul>
{filteredProducts.map(product => (
<li key={product.id}>
{/* 個別商品詳細へのリンク(もしProductDetailルートがあるなら) */}
{/* <Link to={`/products/${product.id}`}>{product.name}</Link> */}
{product.name} ({product.category})
</li>
))}
</ul>
</div>
);
}
export default ProductList;
“`
App.js
にこの ProductList
コンポーネントへのルートを追加します。
“`javascript
// src/App.js (一部変更)
import React from ‘react’;
import { BrowserRouter, Routes, Route, Link } from ‘react-router-dom’;
// … 他のインポート …
import ProductList from ‘./components/ProductList’; // ProductListをインポート
function App() {
return (
<hr />
<Routes>
{/* ... 他のRoute ... */}
{/* 商品リストへのルート */}
{/* /products または /products?category=... にマッチ */}
<Route path="/products" element={<ProductList />} />
{/* ... ProductDetail ルートなど ... */}
</Routes>
</div>
</BrowserRouter>
);
}
“`
これで、/products
にアクセスすると商品リストが表示されます。フィルタリングボタンをクリックすると、URLが /products?category=electronics
のように変化し、それに合わせて ProductList
コンポーネント内で useSearchParams
から取得した category
の値が変わるため、表示される商品リストもフィルタリングされます。
useSearchParams
から返される URLSearchParams
オブジェクトは、get('key')
、getAll('key')
、has('key')
、toString()
といったメソッドを持っており、クエリパラメーターの読み取りに便利です。
setSearchParams
関数は、引数にオブジェクトまたは関数を受け取り、クエリパラメーターを更新します。新しいクエリパラメーターを設定すると、URLが更新され、そのルートをレンダリングしているコンポーネントが再レンダリングされます。
プログラムによる画面遷移 (useNavigate
)
ユーザーがリンクをクリックすることによる画面遷移だけでなく、プログラムの実行フローの中で自動的に別のページへ遷移させたい場面があります。例えば、フォームを送信した後に成功メッセージページへリダイレクトしたり、ユーザーがログインに成功したらダッシュボードへ移動させたりする場合です。
このような「プログラムによる画面遷移」を実現するために、React Router DOM v6では useNavigate
フックが提供されています。useNavigate
フックを呼び出すと、ナビゲーションを実行するための関数が返されます。
例を見てみましょう。簡単なログインフォームがあり、ログインボタンをクリックしたらダッシュボードページに遷移するようなシナリオを考えます。
まず、ログインフォームコンポーネント LoginForm.js
を作成します。
“`javascript
// src/components/LoginForm.js
import React, { useState } from ‘react’;
import { useNavigate } from ‘react-router-dom’; // useNavigateフックをインポート
function LoginForm() {
const [username, setUsername] = useState(”);
const [password, setPassword] = useState(”);
// useNavigateフックを呼び出して、ナビゲーション関数を取得
const navigate = useNavigate();
const handleSubmit = (event) => {
event.preventDefault(); // フォームのデフォルト送信を防ぐ
// ここで実際の認証処理を行う(省略)
console.log('Login attempt with:', username, password);
// 認証成功と仮定して、ダッシュボードページへ遷移する
// navigate('/') または navigate('/dashboard') のように遷移先のパスを指定する
navigate('/'); // 例: ホームページへ遷移
// navigate('/dashboard'); // 例: ダッシュボードページへ遷移
};
return (
ログイン
);
}
export default LoginForm;
“`
次に、App.js
に LoginForm
へのルートを追加します。ダッシュボードへのルートも必要であれば追加しておきます(ここでは簡単のためホームに遷移しています)。
“`javascript
// src/App.js (一部変更)
import React from ‘react’;
import { BrowserRouter, Routes, Route, Link } from ‘react-router-dom’;
// … 他のインポート …
import LoginForm from ‘./components/LoginForm’; // LoginFormをインポート
function App() {
return (
<hr />
<Routes>
{/* ... 他のRoute ... */}
{/* ログインページへのルート */}
<Route path="/login" element={<LoginForm />} />
{/* ダッシュボードなど、ログイン後に遷移する可能性のあるルートも定義しておく */}
{/* <Route path="/dashboard" element={<Dashboard />} /> */}
</Routes>
</div>
</BrowserRouter>
);
}
“`
これで、/login
ページでユーザー名とパスワードを入力し、ログインボタンをクリックすると、handleSubmit
関数が実行され、その中の navigate('/')
(または navigate('/dashboard')
など)によってプログラム的に /
パスへ画面遷移が行われます。
navigate
関数の使い方:
navigate
関数はいくつかの呼び出し方があります。
navigate('/path')
: 指定したパスへ遷移します。ブラウザの履歴スタックに新しいエントリを追加します。これはhistory.push('/path')
に相当します。navigate('/path', { replace: true })
: 指定したパスへ遷移しますが、現在の履歴エントリを置き換えます。ブラウザの「戻る」ボタンで直前のページに戻れなくなります。これはログイン後のリダイレクトなど、ユーザーがログインページに戻るべきではない場合に便利です。history.replace('/path')
に相当します。navigate(-1)
: 履歴を1つ戻ります。ブラウザの「戻る」ボタンを押すのと同じ挙動です。navigate(2)
: 履歴を2つ進みます。ブラウザの「進む」ボタンを押すのと同じ挙動です。navigate('/path', { state: { someData: value } })
: 遷移先に状態データを渡すことができます。遷移先のコンポーネントではuseLocation
フックを使ってlocation.state
からデータを取り出せます。
useNavigate
フックもまた、コンポーネントが <Routes>
の中の <Route>
によってレンダリングされる階層、またはその子孫コンポーネントで使用する必要があります。
ネストされたルート (Nested Routes)
React Router DOM v6の強力な機能の一つに、ネストされたルート(入れ子になったルート)のサポートがあります。これは、特定の親ルートの下に複数の子ルートが存在する場合に非常に便利です。例えば、ダッシュボードの各セクション(設定、プロフィール、レポートなど)や、ブログのカテゴリ別記事一覧とその中の個別記事詳細などが典型的な例です。
ネストされたルートを使うと、親コンポーネント内で子ルートに対応するコンポーネントをレンダリングできます。これにより、共通のレイアウト(サイドバーやタブなど)を持つセクションを簡単に構築できます。
ネストされたルートを定義するには、<Route>
コンポーネントを別の <Route>
コンポーネントの中に子として配置します。そして、親の element
に指定されたコンポーネント内で、子ルートがレンダリングされる場所として <Outlet>
コンポーネントを配置します。
例として、ダッシュボードセクションのネストされたルートを考えます。ダッシュボードには「概要」「設定」「プロフィール」の3つのサブページがあるとします。
まず、各サブページのコンポーネントを作成します。
“`javascript
// src/components/DashboardSummary.js
import React from ‘react’;
function DashboardSummary() {
return (
概要
ダッシュボードの概要情報が表示されます。
);
}
export default DashboardSummary;
// src/components/DashboardSettings.js
import React from ‘react’;
function DashboardSettings() {
return (
設定
ユーザー設定をここで行います。
);
}
export default DashboardSettings;
// src/components/DashboardProfile.js
import React from ‘react’;
function DashboardProfile() {
return (
プロフィール
ユーザープロフィールが表示されます。
);
}
export default DashboardProfile;
“`
次に、これらのサブページをラップする親コンポーネント DashboardLayout.js
を作成します。このコンポーネントには共通のナビゲーションやレイアウト要素を含め、子ルートの内容が表示される場所に <Outlet>
を配置します。
“`javascript
// src/components/DashboardLayout.js
import React from ‘react’;
import { Link, Outlet } from ‘react-router-dom’; // LinkとOutletをインポート
function DashboardLayout() {
return (
ダッシュボード
{/ ダッシュボード共通のサブナビゲーション /}
<hr />
{/* 子ルートがレンダリングされる場所 */}
{/* URLが /dashboard/settings なら <DashboardSettings /> がここに表示される */}
{/* URLが /dashboard/profile なら <DashboardProfile /> がここに表示される */}
{/* URLが /dashboard または /dashboard/ なら、親Routeのindex要素(下記参照)がここに表示される */}
<Outlet />
</div>
);
}
export default DashboardLayout;
“`
最後に、App.js
の <Routes>
の中に、ネストされたルートを定義します。
“`javascript
// src/App.js (一部変更)
import React from ‘react’;
import { BrowserRouter, Routes, Route, Link } from ‘react-router-dom’;
// … 他のインポート …
import DashboardLayout from ‘./components/DashboardLayout’; // 親コンポーネントをインポート
import DashboardSummary from ‘./components/DashboardSummary’; // 子コンポーネントをインポート
import DashboardSettings from ‘./components/DashboardSettings’;
import DashboardProfile from ‘./components/DashboardProfile’;
function App() {
return (
<hr />
<Routes>
{/* ... 他のRoute ... */}
{/* ダッシュボードの親ルート */}
{/* path="/dashboard" にマッチしたら <DashboardLayout /> をレンダリング */}
<Route path="/dashboard" element={<DashboardLayout />}>
{/* ここにネストされた子ルートを定義 */}
{/* index属性を持つRouteは、親パス (/dashboard) に正確にマッチした場合にレンダリングされる */}
{/* /dashboard または /dashboard/ の場合に <DashboardSummary /> を表示 */}
<Route index element={<DashboardSummary />} />
{/* path="settings" は相対パス。親のパス (/dashboard) と組み合わされて /dashboard/settings になる */}
<Route path="settings" element={<DashboardSettings />} />
{/* path="profile" も相対パス。親のパス (/dashboard) と組み合わされて /dashboard/profile になる */}
<Route path="profile" element={<DashboardProfile />} />
{/* 子ルートにマッチしなかった場合のフォールバックも設定可能 */}
{/* <Route path="*" element={<DashboardNotFound />} /> */}
</Route>
</Routes>
</div>
</BrowserRouter>
);
}
“`
この設定により、以下のようになります。
- URLが
/dashboard
または/dashboard/
の場合:<Routes>
はpath="/dashboard"
の<Route>
にマッチします。DashboardLayout
コンポーネントがレンダリングされます。DashboardLayout
内の<Outlet>
の場所には、子ルートの中でindex
属性を持つ<Route index element={<DashboardSummary />} />
のelement
である<DashboardSummary />
がレンダリングされます。
- URLが
/dashboard/settings
の場合:<Routes>
はpath="/dashboard"
の親<Route>
にマッチします。DashboardLayout
コンポーネントがレンダリングされます。- 同時に、親パス
/dashboard
の下の子ルートのうち、path="settings"
の<Route>
がマッチします。 DashboardLayout
内の<Outlet>
の場所には、この子ルートのelement
である<DashboardSettings />
がレンダリングされます。
- URLが
/dashboard/profile
の場合も同様に、DashboardProfile
が<Outlet>
の場所にレンダリングされます。
ネストされたルートの <Link>
の to
プロパティでは、親ルートからの相対パスを指定するのが一般的です(例: "settings"
, "profile"
)。ルートパス(/dashboard
自体)を指したい場合は、v6では "."
を使用します (<Link to=".">
)。以前のバージョンでは ""
(空文字列) を使うことが多かったですが、v6からは "."
が推奨されています。絶対パス (/dashboard/settings
) を指定することも可能ですが、相対パスを使うことで、親ルートのパスが変更されても子ルート側の to
プロパティを変更する必要がなくなるというメリットがあります。
index
ルート (<Route index element={<... />} />
) は、親ルートのパスに正確にマッチした場合にレンダリングされる特別な子ルートです。親ルートがパスを指定している場合、index
子ルートは親パスのデフォルトコンテンツとして機能します。
ネストされたルートと <Outlet>
を使うことで、共通レイアウトを持つ複雑なアプリケーション構造を、より直感的かつコンポーネント指向で記述できるようになります。
404ページの作成
ユーザーがアプリケーションに存在しないURLにアクセスした場合(例: タイプミスや古いリンクなど)、適切な「404 Not Found」ページを表示するのがユーザー体験上望ましいです。
React Router DOMでは、これを簡単に実装できます。<Routes>
コンポーネントは、子として定義された <Route>
を上から順に評価し、現在のURLに最初にマッチした Route
をレンダリングします。この特性を利用して、すべてのルート定義の 最後に path="*"
というワイルドカードパスを持つ <Route>
を配置します。
path="*"
は、それより前に定義されたどのパスにもマッチしなかった場合にマッチします。したがって、これを404ページ用のルートとして使用できます。
まず、404ページ用のコンポーネントを作成します。
“`javascript
// src/components/NotFoundPage.js
import React from ‘react’;
import { useLocation } from ‘react-router-dom’; // 現在のパスを表示するために使用
function NotFoundPage() {
const location = useLocation(); // 現在のロケーション情報を取得
return (
404 – ページが見つかりません
{location.pathname}
というパスのページは見つかりませんでした。
{/ ホームへ戻るリンクなどを追加しても良い /}
{/ ホームに戻る /}
);
}
export default NotFoundPage;
“`
次に、App.js
の <Routes>
の中の、他のすべての <Route>
の定義よりも後ろに、この NotFoundPage
へのルートを追加します。
“`javascript
// src/App.js (一部変更)
import React from ‘react’;
import { BrowserRouter, Routes, Route, Link } from ‘react-router-dom’;
// … 他のインポート …
import NotFoundPage from ‘./components/NotFoundPage’; // NotFoundPageをインポート
function App() {
return (
<hr />
<Routes>
{/* 通常のルート定義 */}
<Route path="/" element={<Home />} />
<Route path="/about" element={<About />} />
<Route path="/contact" element={<Contact />} />
<Route path="/products/:productId" element={<ProductDetail />} />
<Route path="/products" element={<ProductList />} />
<Route path="/login" element={<LoginForm />} />
{/* ネストされたルートもここより前に配置 */}
<Route path="/dashboard" element={<DashboardLayout />}>
{/* ... 子Route ... */}
</Route>
{/* --- ここからが重要 --- */}
{/* どのパスにもマッチしなかった場合に、このルートがマッチする */}
{/* 必ず Routes の最後の方に配置する */}
<Route path="*" element={<NotFoundPage />} />
</Routes>
</div>
</BrowserRouter>
);
}
“`
これで、定義されたどのパスにもマッチしないURLにアクセスがあった場合、path="*"
のルートがマッチし、NotFoundPage
コンポーネントがレンダリングされます。
useLocation
フックは、現在のURLに関する情報(パス名、クエリ文字列、ハッシュなど)を含む location
オブジェクトを返します。404ページで、見つからなかったパスを表示するのに便利です。
NavLink
を使ったアクティブリンクのスタイリング
ナビゲーションバーを作成する際に、ユーザーが現在どのページを見ているかを視覚的に分かりやすくするために、アクティブなリンク(現在表示されているページのリンク)に特別なスタイルを適用したい場合があります。例えば、背景色を変えたり、下線を引いたりするなどです。
React Router DOMは、この目的のために NavLink
という特別なコンポーネントを提供しています。NavLink
は <Link>
とほぼ同じように使えますが、現在のURLが to
プロパティのパスにマッチしている場合に、特定のCSSクラスを適用したり、インラインスタイルを適用したりする機能が追加されています。
NavLink
を使うと、アクティブな状態かどうかを判定して手動でクラスを切り替えるロジックを書く必要がなく、宣言的にアクティブスタイルを適用できます。
例として、先ほどのナビゲーションバーの <Link>
を <NavLink>
に置き換えてみましょう。
“`javascript
// src/App.js (一部変更)
import React from ‘react’;
import { BrowserRouter, Routes, Route, NavLink } from ‘react-router-dom’; // LinkではなくNavLinkをインポート
// … 他のインポート …
function App() {
// アクティブなスタイルを定義
// isActive 引数は、現在のNavLinkがアクティブかどうかを示す真偽値
const activeStyle = {
textDecoration: “underline”,
color: “#007bff”, // 例: 青色に
};
// またはクラス名を適用する場合
const activeClassName = “active-link”;
return (
<hr />
<Routes>{/* ... Routeの定義 ... */}</Routes>
</div>
</BrowserRouter>
);
}
export default App;
“`
NavLink
の style
プロパティにオブジェクトではなく関数を渡しているのがポイントです。この関数は引数として { isActive }
というオブジェクトを受け取ります。isActive
は現在の NavLink
の to
プロパティのパスが現在のURLとマッチしている場合に true
になります。この isActive
の値に基づいて、アクティブ時のスタイルオブジェクトを返す(または非アクティブ時は undefined
を返す)ことで、スタイルを動的に適用できます。
同様に、className
プロパティにも関数を渡すことで、アクティブな場合に特定のCSSクラス名を適用し、それに基づいてスタイルを定義することもできます。
NavLinkのデフォルトのアクティブクラス:
NavLink
は、デフォルトでアクティブなリンクに対して active
というCSSクラス名を適用します。CSS側で .active
または .active-link
のようなセレクタを使ってスタイルを定義することで、簡単にアクティブスタイルを設定できます。
“`css
/ 例: src/App.css または別のCSSファイル /
.active {
text-decoration: underline;
font-weight: bold;
color: #007bff;
}
/ もし className={({ isActive }) => (isActive ? “my-active-class” : “”)} のように使った場合 /
.my-active-class {
/ スタイルを定義 /
}
“`
CSSクラスを使う方法は、スタイルをCSSファイルに集約できるため、より一般的で管理しやすいです。
NavLink
は、アクティブ判定において、指定された to
パスが現在のURLの先頭部分と一致するかどうかを見ます。例えば、/products
という NavLink
は、/products
だけでなく /products/123
というURLにもマッチしてアクティブになります。もし、特定のパスに「完全に一致する場合のみ」アクティブにしたい場合は、end
プロパティを true
に設定します (<NavLink to="/products" end>
)。v6では、親ルートの index
ルート (/dashboard
自体) に対応する NavLink
は、to="."
と end
を一緒に使うのが一般的です。
よくある疑問とトラブルシューティング
React Router DOMを使い始めた際に、いくつか戸惑いやすい点やよくあるエラーがあります。
-
「
useNavigate
やuseParams
などのフックが使えない」というエラー:- 原因: これらのフックは、
BrowserRouter
(または他のルータープロバイダー) のコンテキスト内でレンダリングされるコンポーネントでしか使用できません。 - 解決策: アプリケーション全体、またはフックを使用したいコンポーネントが含まれるツリーの最上位を
<BrowserRouter>
でラップしていることを確認してください。通常はsrc/index.js
(またはmain.jsx
) で<App />
を<BrowserRouter>
で囲みます。
- 原因: これらのフックは、
-
「リンクをクリックしてもページが再読み込みされてしまう」:
- 原因:
react-router-dom
の<Link>
コンポーネントではなく、HTML標準の<a href="...">
タグを使用している可能性があります。 - 解決策: SPA内部のナビゲーションには必ず
<Link to="...">
または<NavLink to="...">
を使用してください。外部サイトへのリンクの場合は<a href="..." target="_blank">
のようなHTMLタグを使用します。
- 原因:
-
「意図しないルートがマッチしてしまう」:
- 原因:
<Route>
コンポーネントが<Routes>
の外に定義されている、またはv6以前のexact
プロパティの考え方が残っている可能性があります。v6では<Routes>
が最適なマッチングを行います。 - 解決策: すべての
<Route>
は必ず<Routes>
の子として定義してください。また、v6では基本的にexact
は不要です。path="/"
は/
にのみマッチし、/about
や/contact
にはマッチしません。より限定的なパス(例:/products/123
)は、より一般的なパス(例:/products
や/
)よりも優先的にマッチします。
- 原因:
-
「URLパラメーター (
useParams
) が取得できない」:- 原因:
<Route path>
でパラメーターが正しく定義されていない(例:path="/products/:productId"
となっているか)、またはuseParams()
を呼び出しているコンポーネントが、そのパラメーターを含む<Route>
によってレンダリングされていない可能性があります。 - 解決策:
Route
のpath
に:parameterName
の形式でパラメーターを正しく定義し、useParams
を呼び出しているコンポーネントが、そのRoute
のelement
として直接、または親ルートの<Outlet>
を通じてレンダリングされていることを確認してください。useParams
から取得する際のキー名は、path
で定義した:parameterName
から:
を除いた名前 (parameterName
) と一致させる必要があります。
- 原因:
-
React Router v5 から v6 への移行で困っている:
- v6ではいくつかの重要な変更点があります。
Switch
->Routes
: ルート定義のコンテナがSwitch
からRoutes
に変わりました。component
/render
->element
:<Route>
でレンダリングする要素を指定するプロパティがcomponent
やrender
からelement
に変更され、<ComponentName />
の形式で指定するようになりました。useHistory
->useNavigate
: プログラムによる遷移のためのフックがuseHistory
からuseNavigate
に変わりました。使い方も少し異なります。exact
プロパティは基本的に不要になりました。- ネストされたルートの定義方法や、子ルートをレンダリングする
<Outlet>
コンポーネントが導入されました。 - 相対パスの扱い方が変わりました (
.
や..
で親や祖先のパスを指定)。
- 解決策: 公式ドキュメントの移行ガイド (Migration Guide) を参照するか、v6の記法に合わせてコードを書き直してください。この記事はv6を前提に書かれているため、参考にしてください。
- v6ではいくつかの重要な変更点があります。
これらの点に注意しながらコードを書くことで、React Router DOMをスムーズに使いこなせるようになるはずです。
より発展的なトピック(簡単な触りだけ)
この記事ではReact Router DOMの基本に焦点を当てましたが、実際にはさらに多くの機能や応用方法があります。ここではいくつか簡単な触りだけ紹介します。
- レイアウトルート (Layout Routes): ネストされたルートと
Outlet
を使うことで、ヘッダー、サイドバー、フッターなどの共通レイアウトの中に子ルートの内容を表示する構造を簡単に構築できます。これは非常に一般的なSPAのパターンです。 - 認証・認可によるルートガード (Protected Routes): 特定のページ(例: ユーザー設定、管理画面)にアクセスできるユーザーを制限したい場合があります。これは、現在のユーザーがログインしているか、必要な権限を持っているかを確認し、条件を満たさない場合はログインページやエラーページにリダイレクトする処理をルート定義に組み込むことで実現できます。通常は、ログイン状態をチェックするラッパーコンポーネントを作成し、その中で
useNavigate
や<Navigate>
コンポーネント(特定の条件が満たされた場合にリダイレクトを行うコンポーネント)を使用します。 -
Code Splitting (コード分割) と組み合わせる: アプリケーションの規模が大きくなると、すべてのコンポーネントのJavaScriptコードを最初のページロード時にまとめてダウンロードするのは非効率です。React Router DOMとReactの
React.lazy()
およびSuspense
を組み合わせることで、特定のルートにアクセスがあったときに初めてそのルートに対応するコンポーネントのコードを遅延ロード(分割ロード)させることができます。これにより、初期ロード時間を短縮できます。
“`javascript
import React, { lazy, Suspense } from ‘react’;
import { BrowserRouter, Routes, Route } from ‘react-router-dom’;// コンポーネントを遅延ロード
const LazyAbout = lazy(() => import(‘./components/About’));
const LazyContact = lazy(() => import(‘./components/Contact’));function App() {
return (
{/ 遅延ロードされるコンポーネントが表示されるまでのフォールバックUI /}
Loading…\
}>
{/ lazyでインポートしたコンポーネントをelementに指定 /}
);
}
``
useScrollRestoration` フックを使うことで、この挙動を制御できます。
* **スクロールの復元 (Scroll Restoration):** ページ遷移後、多くの場合ページの上部にスクロールしたいですが、ブラウザの「戻る」ボタンで前のページに戻ったときは、元のスクロール位置に戻りたいはずです。React Router DOMの
これらの発展的なトピックについては、React Router DOMの公式ドキュメントや、より詳細な解説記事を参照することをおすすめします。しかし、まずはこの記事で解説した基本的な使い方をしっかりとマスターすることが、これらの応用に進むための第一歩です。
まとめ
この記事では、Reactアプリケーションにクライアントサイドルーティングを導入するための標準ライブラリである React Router DOM について、その必要性から基本的な使い方、そして主要な機能までを詳しく解説しました。
- SPAにおけるスムーズな画面遷移とURL・履歴管理の課題を解決するのがクライアントサイドルーティングです。
- React Router DOMは、
BrowserRouter
、Routes
、Route
、Link
といったコンポーネントを使って、宣言的にルーティングを設定できます。 BrowserRouter
はアプリケーション全体をラップし、ブラウザの履歴APIとの連携を担います。Routes
は複数のRoute
を管理し、現在のURLにマッチする最適なRoute
をレンダリングします。Route
は特定のパスと表示する要素(コンポーネント)を関連付けます。Link
はSPA内でのページ再読み込みなしのナビゲーションリンクを作成します。useParams
フックでURLパラメーターを取得し、動的なコンテンツ表示に利用できます。useSearchParams
フックでクエリパラメーターを読み書きし、リストのフィルタリングなどに利用できます。useNavigate
フックで、プログラムによる画面遷移(リダイレクトなど)を実行できます。- ネストされたルートと
Outlet
コンポーネントを使うことで、共通レイアウトを持つ複雑なページ構造を効率的に構築できます。 path="*"
の<Route>
を使って404ページを実装できます。NavLink
を使うと、アクティブなリンクに自動的にスタイルを適用できます。
React Router DOMは非常に柔軟で強力なライブラリであり、これらの基本的な要素を理解すれば、ほとんどのSPAで必要とされるルーティング機能を実装できるようになります。
まずは小さなアプリケーションで実際にこれらのコンポーネントを使ってみることから始めてください。コードを書き、ブラウザで挙動を確認し、エラーに遭遇したら原因を探るというプロセスを通じて、理解が深まります。
次のステップ
- この記事のコード例を実際に自分のReactプロジェクトで試してみる。
- 簡単なブログアプリケーションや商品リスト/詳細ページのようなものを、今回学んだ機能を使って実装してみる。
- React Router DOMの公式ドキュメント(https://reactrouter.com/docs/)を参照し、さらに詳しい情報や高度な機能について学ぶ。
- React Router DOMを使った認証付きルートやコード分割などの応用例について調べてみる。
React Router DOMをマスターして、あなたのReactアプリケーションに強力なナビゲーション機能を実装しましょう!