はい、承知いたしました。React RouterのLink
コンポーネントに焦点を当て、詳細な解説を含む約5000語の記事を作成します。
React Router Link を使ってみよう!SPAの要、分かりやすい解説
Webアプリケーション開発において、ページ間の遷移はユーザー体験の根幹をなす要素です。ユーザーがアプリケーション内をスムーズに移動できるかどうかは、そのアプリケーションの使いやすさを大きく左右します。従来のWebサイトでは、ページ遷移はブラウザがサーバーにリクエストを送り、新しいHTMLページを完全に読み込み直すという仕組みが一般的でした。これはシンプルで確実な方法ですが、遷移ごとに画面全体が再描画されるため、一瞬の空白時間が発生したり、アプリケーション全体が一貫性を失ったりといった課題がありました。
現代のWeb開発、特にSingle Page Application (SPA) の台頭により、このページ遷移の概念は大きく変わりました。SPAでは、初期読み込み時にアプリケーションの全体(または大部分)が読み込まれ、その後の画面遷移はブラウザがサーバーにフルリクエストを送るのではなく、JavaScriptがブラウザの表示内容を動的に書き換えることで実現されます。これにより、ページ遷移が高速になり、ユーザーはデスクトップアプリケーションに近い滑らかな操作感を得ることができます。
しかし、SPAでどのようにしてブラウザの履歴管理(「戻る」「進む」ボタンの機能)や、特定のURLへの直接アクセス(例:/about
というURLを直接入力してそのページを表示する)を実現するのでしょうか?ここで必要になるのが、「クライアントサイドルーティング」という技術です。
Reactにおけるクライアントサイドルーティングのデファクトスタンダードとも言えるライブラリが、「React Router」です。React Routerは、宣言的な方法でアプリケーションのルーティング(URLと表示するコンポーネントのマッピング)を定義することを可能にします。そして、このReact Routerの機能の中でも、ユーザーがアプリケーション内を移動するための主要な手段を提供するのが、今回焦点を当てるLink
コンポーネントです。
Link
コンポーネントは、従来のHTMLの<a>
タグのような見た目や機能を提供しますが、その内部の挙動は大きく異なります。<a>
タグがデフォルトでブラウザにフルリロードを伴う新しいページへの遷移を指示するのに対し、Link
コンポーネントはReact Routerと連携し、SPAの枠組みの中で、ブラウザの履歴APIを利用してURLを変更し、対応するコンポーネントを再描画するというスマートな遷移を実現します。
この記事では、React RouterのLink
コンポーネントの基本的な使い方から、その重要なProps、さらに高度な使い方や、他のナビゲーション手段(<a>
タグ、NavLink
、useNavigate
)との違いについて、約5000語の詳細な解説を通して深く掘り下げていきます。この記事を読み終える頃には、React RouterのLink
コンポーネントを自信を持って使いこなし、より快適で効率的なSPA開発ができるようになっているでしょう。
さあ、React RouterのLink
コンポーネントの世界へ飛び込んでみましょう。
Webにおけるページ遷移の基礎:<a>
タグとフルリロード
React RouterのLink
コンポーネントの重要性を理解するためには、まず伝統的なWebにおけるページ遷移の仕組みを理解しておくことが役立ちます。
最も基本的で歴史のあるページ遷移の方法は、HTMLの<a>
タグを使用することです。<a>
タグはアンカー要素と呼ばれ、href
属性に指定されたURLへハイパーリンクを張るために使われます。
html
<a href="/about">About Us</a>
ユーザーがこのリンクをクリックすると、ブラウザはhref
属性に指定されたURLに対して新しいHTTPリクエストをサーバーに送信します。サーバーはそのリクエストを受け取り、対応するHTMLファイルを生成(または取得)してブラウザに返します。ブラウザはそのHTMLファイルを解析し、CSSやJavaScriptなどの関連リソースを読み込み、ページ全体をゼロから再描画します。このプロセスは「フルリロード」と呼ばれます。
フルリロードはシンプルで理解しやすい仕組みですが、いくつかのデメリットがあります。
- 遅延: サーバーへのリクエスト、サーバーでの処理、レスポンスの送信、ブラウザでの再描画という一連のプロセスには時間がかかります。特にネットワーク環境が悪い場合や、サーバーの負荷が高い場合には、ユーザーは次のページが表示されるまでの待ち時間を長く感じることになります。
- ユーザー体験の中断: ページ全体が再描画されるため、画面が一瞬真っ白になったり、要素がガタついたりすることがあります。これはアプリケーションの一貫性を損ない、ユーザーに不快感を与える可能性があります。
- 状態の喪失: 現在のページのJavaScriptによる状態(例:モーダルの表示状態、フォームの入力内容、アニメーションの進行度など)は、フルリロードによってすべてリセットされてしまいます。
クライアントサイドルーティングとSPA
これらのフルリロードのデメリットを克服するために登場したのが、Single Page Application (SPA) とクライアントサイドルーティングです。SPAでは、アプリケーションの起動時に必要なリソースをまとめて(あるいは分割して少しずつ)読み込み、その後はサーバーとのやり取りを最小限に抑えます。
SPAにおけるページ遷移は、ブラウザのJavaScriptが担当します。ユーザーがリンクをクリックしたり、特定の操作を行ったりした際に、JavaScriptが新しいコンテンツを取得(API通信など)し、DOMを動的に操作して画面の一部または全体を書き換えます。このとき、ページ全体を再読み込みするのではなく、必要な部分だけが更新されます。
しかし、画面の内容だけをJavaScriptで書き換えるだけでは不都合が生じます。
- URLが変わらない: 画面内容は変わったのに、ブラウザのアドレスバーに表示されているURLが最初のページのままになってしまいます。これでは、ユーザーは現在どのページにいるのか分からなくなりますし、特定のページへのブックマークや共有ができなくなります。
- 「戻る」「進む」ボタンが機能しない: ブラウザの履歴に新しいエントリが追加されないため、ユーザーがブラウザの「戻る」ボタンをクリックしても、期待通りに前の画面に戻ることができません。
これらの問題を解決するために、SPAでは「History API」というブラウザの機能を利用します。History APIを使用すると、JavaScriptからブラウザのアドレスバーのURLを変更したり、履歴スタックに新しいエントリを追加したり、履歴スタック内のエントリを置き換えたりすることができます。これにより、画面の表示内容とブラウザのURL・履歴を同期させることが可能になります。
クライアントサイドルーティングライブラリ(React Routerなど)は、このHistory APIを抽象化し、開発者が宣言的かつ効率的にSPAのルーティングを管理できるようにするツールです。そして、Link
コンポーネントは、このクライアントサイドルーティングの仕組みを利用して、SPA内でのナビゲーションを実現するためのインターフェースを提供するのです。
React Routerとは
React Routerは、Reactアプリケーションにおける宣言的なルーティングのための標準的なライブラリです。Reactのコンポーネントベースのパラダイムと非常に相性が良く、ルーティングの設定もコンポーネントとして扱うことができます。
React Routerの主な役割は以下の通りです。
- URLとコンポーネントのマッピング: 特定のURLパス(例:
/about
,/users/:id
)が要求されたときに、どのReactコンポーネントを表示するかを定義します。 - ナビゲーションの管理: ユーザーがアプリケーション内を移動するための手段を提供します(例:
Link
コンポーネント、useNavigate
フック)。これらの手段は、ブラウザのHistory APIを利用してURLを変更し、React Routerにルーティングの更新を通知します。 - ルーティング情報の提供: 現在のURL、パスパラメータ、クエリストリング、履歴の状態などを、表示されているコンポーネントからアクセスできるようにします(例:
useParams
,useLocation
,useMatch
フック)。
React Routerの主要なコンポーネント/フックには以下のようなものがあります。
BrowserRouter
: ブラウザのHistory APIを使用したルーティングの基盤となるコンポーネント。アプリケーション全体をこれで囲みます。Routes
: ルーティングルールを定義するコンポーネント群をまとめるコンテナ。Route
: 特定のパスと、そのパスにマッチしたときに表示するコンポーネントをマッピングするコンポーネント。Link
: SPA内で別のルートへ遷移するためのナビゲーションリンクを生成するコンポーネント。NavLink
:Link
とほぼ同じですが、現在のURLにマッチしている場合に特別なスタイルを適用できるコンポーネント。useNavigate
: プログラムによるナビゲーション(ユーザー操作以外での遷移、ボタンクリック時の遷移など)を行うためのフック。useLocation
: 現在のURL情報(パス名、クエリストリング、ハッシュ、stateなど)を取得するためのフック。useParams
: URLのパスパラメータを取得するためのフック。
これらのコンポーネントやフックを組み合わせることで、複雑なルーティングを持つSPAも効率的に構築できます。そして、その中でもユーザーとのインタラクションの最前線に立ち、ナビゲーションの起点となるのが、今回学ぶLink
コンポーネントなのです。
Linkコンポーネントの基礎:SPAでのナビゲーションの要
Link
コンポーネントは、React Routerにおいて、ユーザーが別のページやルートへ遷移するための主要なUI要素です。見た目は一般的なHTMLの<a>
タグと同じように表示されますが、クリックされたときの挙動が異なります。
前述の通り、HTMLの<a>
タグはデフォルトでブラウザに指定されたURLへのフルリロードを指示します。一方、Link
コンポーネントは、クリックされるとイベントを横取り(preventDefault()
のようなことを内部で行う)し、React Routerに対して指定されたパスへの遷移を指示します。React Routerは、History APIを使用してブラウザのアドレスバーのURLを変更し、履歴スタックを更新し、その後、新しいURLに対応するコンポーネントをレンダリングします。このプロセス全体がJavaScriptの制御下で行われるため、ページ全体のフルリロードは発生しません。
<a>
タグとの比較
特徴 | <a> タグ |
Link コンポーネント (React Router) |
---|---|---|
遷移方法 | フルリロード(サーバーへのHTTPリクエスト) | クライアントサイドルーティング (History API) |
画面の挙動 | ページ全体が再描画される | DOMの一部が書き換えられる(SPAのまま) |
URLの扱い | 指定されたURLへ直接リクエスト | React Routerが管理する内部ルートへ遷移 |
履歴管理 | ブラウザのデフォルト履歴機能 | History APIを利用した履歴管理 |
状態の保持 | フルリロードでリセットされる | アプリケーションの状態は維持される(SPA) |
用途 | 外部サイトへのリンク、ファイルダウンロード | SPA内部のルート間遷移 |
必須ライブラリ | なし | React Router |
このように、Link
コンポーネントはSPA内部でのスムーズな遷移を実現するために設計されています。外部サイトへのリンクなど、明示的にフルリロードが必要な場合を除き、React Routerを使用しているアプリケーション内でのナビゲーションにはLink
コンポーネントを使用するのが基本です。
基本的な使い方
Link
コンポーネントの最も基本的な使い方は、遷移先のパスをto
というPropsに指定することです。
まず、React Routerをインストールしていない場合はインストールします。
“`bash
npm install react-router-dom
または
yarn add react-router-dom
“`
アプリケーションのルートコンポーネント(通常はApp.js
やindex.js
など)をBrowserRouter
で囲みます。
“`jsx
// index.js または App.js
import React from ‘react’;
import ReactDOM from ‘react-dom/client’;
import { BrowserRouter } from ‘react-router-dom’;
import App from ‘./App’;
const root = ReactDOM.createRoot(document.getElementById(‘root’));
root.render(
);
“`
次に、ルーティングを定義します。
“`jsx
// App.js
import React from ‘react’;
import { Routes, Route, Link } from ‘react-router-dom’;
function Home() {
return
Home Page
;
}
function About() {
return
About Page
;
}
function Contact() {
return
Contact Page
;
}
function App() {
return (
<Routes>
<Route path="/" element={<Home />} />
<Route path="/about" element={<About />} />
<Route path="/contact" element={<Contact />} />
</Routes>
</div>
);
}
export default App;
“`
この例では、ナビゲーションバーに3つのLink
コンポーネントがあります。
<Link to="/">Home</Link>
:/
パスへのリンクです。クリックすると、Home
コンポーネントが表示されます。<Link to="/about">About</Link>
:/about
パスへのリンクです。クリックすると、About
コンポーネントが表示されます。<Link to="/contact">Contact</Link>
:/contact
パスへのリンクです。クリックすると、Contact
コンポーネントが表示されます。
これらのLink
をクリックしても、ページ全体がリロードされることはありません。ブラウザのアドレスバーのURLが変わり、それに応じて<Routes>
内で定義されたRoute
がマッチし、対応するコンポーネントがレンダリングされます。
Linkコンポーネントの主要なProps
Link
コンポーネントは、基本的なto
Props以外にも、様々なカスタマイズや高度な機能を提供するPropsを持っています。ここでは、主要なPropsについて詳しく見ていきましょう。
to
(必須)
遷移先のパスを指定するPropsです。最も基本的で重要なPropsであり、省略することはできません。to
には文字列またはオブジェクトを指定できます。
1. 文字列による指定:
最も一般的な方法です。絶対パスまたは相対パスを指定できます。
-
絶対パス:
/
で始まるパスです。アプリケーションのルートからの絶対位置を示します。jsx
<Link to="/">トップページへ</Link>
<Link to="/users/123">ユーザー詳細へ</Link>
<Link to="/products?category=electronics">製品一覧へ (クエリ付き)</Link> -
相対パス:
/
で始まらないパスです。現在のURLからの相対位置を示します。例えば、現在のURLが
/users/profile
で、<Link to="edit">編集</Link>
とした場合、遷移先は/users/edit
となります。また、<Link to="../">親ディレクトリへ</Link>
とした場合は、/users
へ遷移します。相対パスはネストされたルーティングで特に便利です。後ほど詳細を説明します。jsx
// 例: 現在のURLが /users/123 の場合
<Link to="edit">このユーザーを編集</Link> {/* -> /users/123/edit */}
<Link to="../">ユーザー一覧へ</Link> {/* -> /users */}
<Link to="../../">トップへ</Link> {/* -> / */}
2. オブジェクトによる指定:
より複雑なURL(クエリストリング、ハッシュフラグメント)や、遷移先に情報を渡したい場合に使用します。to
Propsに以下のプロパティを持つオブジェクトを指定します。
pathname
: 遷移先のパス名(文字列)。/users/123
など。search
: クエリストリング(文字列)。?category=electronics&sort=price
など。先頭の?
を含める必要があります。hash
: ハッシュフラグメント(文字列)。#section-title
など。先頭の#
を含める必要があります。-
state
: 遷移先のルートで利用できる状態(任意の値)。オブジェクトなどを渡せます。“`jsx
<Link
to={{
pathname: ‘/products’,
search: ‘?category=electronics&sort=price’,
hash: ‘#description’,
state: { fromProductList: true, page: 1 } // stateを渡す
}}製品一覧へ (オブジェクト形式)
“`遷移先 (
/products
にマッチするコンポーネント) では、useLocation
フックを使ってこれらの情報(pathname
,search
,hash
,state
)を取得できます。“`jsx
import { useLocation } from ‘react-router-dom’;function ProductList() {
const location = useLocation();
console.log(location.pathname); // ‘/products’
console.log(location.search); // ‘?category=electronics&sort=price’
console.log(location.hash); // ‘#description’
console.log(location.state); // { fromProductList: true, page: 1 }// … レンダリングロジック …
}
“`state
は、ページ遷移時に一時的な情報(例: モーダルを開いていたか、スクロール位置、前のページからのデータなど)を渡すのに非常に便利です。ブラウザのリロード時には失われる情報であることに注意してください。
replace
(boolean)
このPropsをtrue
に設定すると、クリックによる遷移が、ブラウザの履歴スタックに新しいエントリを追加するのではなく、現在の履歴エントリを置き換えます。デフォルトはfalse
で、新しいエントリが追加されます。
履歴スタックの置き換えは、特定のシナリオで役立ちます。例えば、ユーザーがログインした後にホームページにリダイレクトする場合、ログインページに戻れないようにするためにreplace={true}
を使用することがよくあります。
jsx
// ログイン成功後のリダイレクトリンク(例)
// 通常はプログラムによる遷移 (useNavigate) で行うことが多いですが、Linkでも可能
<Link to="/dashboard" replace={true}>ダッシュボードへ</Link>
ユーザーがこのリンクをクリックすると、履歴スタックは [..., ログインページ]
から [..., ダッシュボードページ]
のように変わります。これにより、ユーザーは「戻る」ボタンでログインページに戻ることはできません。
state
(any)
これはto
Propsのオブジェクト形式で指定できるstate
と同じ機能です。Link
コンポーネントのPropsとして直接指定することもできます。どちらの書き方でも結果は同じです。
jsx
// to={{ pathname: '/some-path', state: { data: '...' } }} と同じ
<Link to="/some-path" state={{ data: 'some value' }}>
状態を渡して遷移
</Link>
state
Propsは、to
Propsが文字列で指定されている場合でも使用できます。
jsx
<Link to="/users/456" state={{ fromList: true }}>
ユーザー456の詳細へ
</Link>
relative
(‘route’ | ‘path’) (v6.4+)
このPropsは、to
Propsに相対パス(/
で始まらないパス)を指定した場合の基準点を変更します。React Router v6.4で導入された機能です。
relative="path"
(デフォルト):to
に指定された相対パスは、現在のURLパスを基準とします。例えば、現在のURLが/users/123
でto="../"
と指定した場合、これは現在のパス/users/123
の「親ディレクトリ」という意味になり、結果として/users
に遷移します。relative="route"
:to
に指定された相対パスは、現在アクティブになっているRoute
コンポーネントのパスを基準とします。これは、ネストされたルーティングで特に便利です。
例を見てみましょう。以下のようなルーティングとコンポーネントがあるとします。
“`jsx
// App.js
import { Routes, Route, Link } from ‘react-router-dom’;
import Layout from ‘./Layout’;
import Users from ‘./Users’;
import UserDetail from ‘./UserDetail’;
function App() {
return (
);
}
// Layout.js (簡単なレイアウトコンポーネント)
import { Link, Outlet } from ‘react-router-dom’;
function Layout() {
return (
My App
);
}
// Users.js (ユーザー一覧)
import { Link, Outlet } from ‘react-router-dom’;
function Users() {
const users = [{ id: 1, name: ‘Alice’ }, { id: 2, name: ‘Bob’ }];
return (
ユーザー一覧
-
{users.map(user => (
- {user.name} {/ 相対パス: ‘1’, ‘2’ /}
))}
);
}
// UserDetail.js (ユーザー詳細)
import { useParams, Link } from ‘react-router-dom’;
function UserDetail() {
const { userId } = useParams();
return (
ユーザー詳細: {userId}
{/ ここで Link to=”../” を使う場合 /}
{/ ユーザー一覧に戻る /}
{/ ユーザー一覧に戻る (route相対) /}
);
}
“`
ユーザーが /users/1
のページ(UserDetail
が表示されている状態)にいるとします。
-
relative="path"
(デフォルト): 現在のURLは/users/1
です。to="../"
は現在のURLのパス/users/1
の親ディレクトリ、つまり/users
を指します。<Link to="../">
は/users
へ遷移します。これは期待通りの挙動かもしれません。 -
relative="route"
: 現在アクティブな最も内側のRoute
は<Route path=":userId" element={<UserDetail />} />
です。その親のRoute
は<Route path="users" element={<Users />}>
です。<Link to="../" relative="route">
は、この親のRoute
のパス/users
を基準として、その親(/
)を指します。つまり/
へ遷移します。これは多くの場合、期待する挙動ではないかもしれません。
では、relative="route"
はどのような場合に役立つのでしょうか?ネストされたルーティングのコンテキストで、特定の親ルートに戻りたい場合などです。
例えば、/users/1/edit
のようなルートがあり、編集ページからユーザー詳細 /users/1
に戻るリンクを作りたいとします。
“`jsx
// UserEdit.js (ユーザー編集)
import { useParams, Link } from ‘react-router-dom’;
function UserEdit() {
const { userId } = useParams();
return (
ユーザー編集: {userId}
{/*
現在のURLが /users/1/edit の場合:
to=”../” (relative=”path”): /users/1 に遷移 (OK)
to=”../” relative=”route”: このルートは /users/:userId/edit となるはずなので、その親、つまり /users/:userId つまり /users/1 に遷移 (OK)
... あれ?同じ挙動になるのでは?
そうです、単純な ../ の場合は同じになりがちです。
relative="route" は、Linkがレンダリングされているルートの"定義パス"からの相対パスを解決します。
例えば、LinkがUserEditコンポーネント内にあり、UserEditが <Route path="edit" element={<UserEdit />} /> にマッチしている場合、
relative="route" の場合の基準は、その親 Route のパス、つまり /users/:userId となります。
to="../" は、この /users/:userId から見て一つ上の階層、つまり /users を指します。
したがって、URLが /users/1/edit の場合、Link to="../" relative="route"> は /users に遷移します。
*/}
{/* ユーザー詳細に戻るなら /users/1 へ明示的に飛ぶか、
relative="path" (デフォルト) で to="../" を使うのが分かりやすい
Link to={`/users/${userId}`}>ユーザー詳細に戻る</Link>
または
<Link to="../">ユーザー詳細に戻る</Link> // relative="path" がデフォルト
*/}
{/* relative="route" の例として挙げられるのは、特定の親ルート内のサブページへのリンクを、
その親ルートのコンポーネント内から相対的に張る場合などです。
例えば、ユーザー詳細ページ (/users/:userId) 内で、
「コメント (/users/:userId/comments)」や「アクティビティ (/users/:userId/activity)」へのリンクを作る場合。
UserDetailコンポーネントは /users/:userId ルートにマッチしています。
*/}
{/* UserDetail.js 内での例 */}
{/* URLが /users/1 の場合: */}
{/* <Link to="comments">コメントを見る</Link> // relative="path" -> /users/1/comments (OK) */}
{/* <Link to="comments" relative="route">コメントを見る</Link> // relative="route" -> /users/1/comments (OK) */}
{/* 違いが出やすいのは、ルート定義のパスと現在のURLの階層が異なる場合など。
例えば、/users/:userId/edit にマッチするコンポーネント内で、
そのコンポーネントをレンダリングしている Route の定義パスからの相対で戻りたい場合。
<Route path="edit" element={<UserEdit />} /> は /users/:userId の子ルート。
UserEditコンポーネント内で <Link to="../" relative="route"> とすると、
これは /users/:userId から見て ../ なので /users に遷移します。
*/}
{/* この例では、/users/1/edit から /users に戻るリンクになる */}
<Link to="../" relative="route">ユーザー一覧に戻る (relative="route")</Link>
{/* 一方、<Link to="../"> (relative="path") は、/users/1/edit から見て ../ なので /users/1 に遷移 */}
<Link to="../">ユーザー詳細に戻る (relative="path")</Link>
</div>
);
}
``
relative=”route”は、Linkが配置されているコンポーネントがマッチしている
Routeコンポーネントのパス定義(例:
path=”:userId”`)からの相対で解決したい場合に利用します。これにより、現在のURLの実際のセグメント数に関わらず、定義上の親ルートへの相対リンクなどを書きやすくなります。
少し理解が難しい機能ですが、ネストされたルーティングを多用する際に、意図した通りの相対パス解決を行うために覚えておくと役立ちます。多くの場合、デフォルトの relative="path"
で十分です。
preventScrollReset
(boolean) (v6.4+)
このPropsをtrue
に設定すると、ナビゲーション時に自動的に行われるウィンドウのスクロール位置リセットを防ぎます。デフォルトはfalse
で、新しいページに遷移した際にウィンドウのスクロール位置が最上部(0,0)にリセットされます。
SPAでは、画面の一部分だけが更新されることが多いため、ページ遷移してもスクロール位置が維持されると、ユーザーが混乱したり、コンテンツを見逃したりする可能性があります。そのため、デフォルトでスクロール位置をリセットするのは妥当な挙動です。
しかし、特定のケースではスクロール位置を維持したい場合があります。例えば、長いリストを表示していて、そのリスト内の要素をクリックして詳細ページに遷移し、その後ブラウザの「戻る」ボタンや、リストページに戻るリンクで戻ってきた際に、詳細を見る前にスクロールしていた位置に戻ってほしい、といった場合です。
このようなシナリオでは、preventScrollReset={true}
を設定することで、Linkクリック時の自動スクロールリセットを防ぐことができます。ただし、これはそのLinkをクリックした場合に限られます。ブラウザの「戻る/進む」ボタンでの遷移や、useNavigate
を使った遷移には影響しません。React Router v6.4からは、スクロール位置の復元はScrollRestoration
コンポーネントや、RouterProviderなどの新しいAPIでより柔軟に制御できるようになっています。preventScrollReset
は、個別のLink
での挙動を調整するためのものです。
jsx
<Link to="/long-list" preventScrollReset={true}>
長いリストページに戻る (スクロール位置維持)
</Link>
その他のProps
Link
コンポーネントは、HTMLの<a>
タグが受け付ける多くの標準的なHTML属性もPropsとして受け付けます。これらは、生成される<a>
要素にそのまま適用されます。
className
: CSSクラスを指定します。スタイリングに利用します。style
: インラインスタイルを指定します。id
: 要素のIDを指定します。title
: ツールチップとして表示されるテキストを指定します。onClick
: クリックイベントハンドラを指定します。Link
によるナビゲーションの前に実行される処理を記述できます。後述。target
: リンクを開くウィンドウを指定します (_blank
で新しいタブなど)。ただし、_blank
以外を指定すると、内部的には<a>
タグのデフォルトの挙動(フルリロード)になる可能性があるため、外部サイトへのリンクなど、明示的にフルリロードが必要な場合にのみ使用するのが安全です。SPA内部リンクで新しいタブを開きたい場合は、target="_blank"
とrel="noopener noreferrer"
をセットで使い、同時にonClick
でevent.preventDefault()
してReact Routerによる遷移を防ぐ、という工夫が必要になる場合があります(または単に通常の<a>
タグを使う)。
“`jsx
console.log(‘Settings link clicked’)}
Settings
“`
これらのPropsを使うことで、Link
コンポーネントの見た目や基本的な挙動をカスタマイズできます。
to
Propの詳細な使い方:パスの指定方法
to
PropはLink
コンポーネントの核となる部分です。文字列とオブジェクト、そして相対パスの使い分けについて、もう少し詳しく見ていきましょう。
文字列による指定
最もシンプルで直感的な方法です。
-
絶対パス:
/
: アプリケーションのルートパス。/about
:/about
という正確なパス。/users/123
:/users/123
というパス。パスパラメータを含むルート (<Route path="/users/:userId">
) にマッチします。/products?category=electronics#description
: クエリストリングとハッシュフラグメントを含むパス。
文字列でクエリストリングやハッシュを指定する場合、これらは単なる文字列の一部として扱われます。遷移先のコンポーネントでこれらの情報(
?category=...
や#...
)を取得するには、useLocation
フックを使用する必要があります。 -
相対パス:
/
で始まらないパス。現在のURLを基準とします(relative="path"
の場合)。./
: 現在のパス自体。..
: 現在のパスの親ディレクトリ。../..
: 現在のパスから2階層上のディレクトリ。edit
: 現在のパスに/edit
を加えたパス。例:/users/123
->/users/123/edit
相対パスは、特にネストされたルーティング構造を持つアプリケーションで便利です。コンポーネントがどの親ルートの下にレンダリングされているかを意識せずに、相対的なリンクを張ることができます。ただし、意図しないパスに遷移しないように、現在のルーティング構造と相対パスの解決ルールを正確に理解しておく必要があります。
オブジェクトによる指定
より構造化された方法で遷移先を指定できます。パス、クエリストリング、ハッシュ、そして状態を明示的に分離して指定します。
“`jsx
<Link
to={{
pathname: ‘/search’,
search: ‘?query=react&page=1’,
hash: ‘#results’,
state: { from: ‘homepage’ }
}}
検索結果へ
“`
pathname
: 必須ではありませんが、パスを指定する場合に使用します。省略すると現在のpathname
が使われます。-
search
: クエリストリングを指定します。URLSearchParams
オブジェクトを使うと、クエリストリングの構築が容易になります。``jsx
?${params.toString()}` // “?query=react&page=1” を生成
const params = new URLSearchParams({ query: 'react', page: '1' });
<Link
to={{
pathname: '/search',
search:
}}検索結果へ (URLSearchParams)
``
searchプロパティの値は文字列である必要があります。
URLSearchParams`を使うとオブジェクトから文字列への変換が簡単に行えます。 -
hash
: ハッシュフラグメントを指定します。ページ内の特定のセクションへのリンクに使用されます。SPAでは、ハッシュが変更されても通常はフルリロードは起きず、ブラウザがそのIDを持つ要素までスクロールします。 -
state
: 遷移先に任意のデータを渡すことができます。これはURLの一部にはなりませんし、ブラウザのリロードや直接URL入力時には失われます。セッションストレージやローカルストレージを使わずに、一時的に状態を渡したい場合に便利です。例えば、リストページから詳細ページへ遷移する際に、リストページでのスクロール位置やフィルタリング条件をstate
として渡し、詳細ページから戻ってきたときにその状態を復元するために利用できます。
相対パスと絶対パスの使い分け
-
絶対パス (
/
で始まる):- アプリケーション内の明確な固定パスへのリンクに最適です。
- ナビゲーションメニュー(ヘッダーやフッターなど)のように、アプリケーション内のどこからでも同じ場所へリンクしたい場合に主に使用します。
- 現在のURLやコンポーネントの配置に依存しないため、予測しやすいです。
-
相対パス (
/
で始まらない):- ネストされたルーティング構造を持つアプリケーションで役立ちます。
- 現在のコンポーネントやURLコンテキストからの相対的な位置へのリンクに使います。
- 例: ユーザー詳細ページ
/users/:userId
の中で、そのユーザーに関連するサブページ(例:/users/:userId/posts
)へのリンクを張る場合、./posts
という相対パスを使えば、userId
が何であっても正しく/users/:userId/posts
に解決されます。 - 親ルートに戻る (
../
) など、階層構造を移動する際に便利です。 relative
Propsを使うことで、相対パスの基準点を変更できます(上級)。
どちらを使うべきかは、リンクの用途やアプリケーションのルーティング構造によって判断します。一般的には、グローバルなナビゲーションには絶対パスを、特定のセクションやリスト内のアイテムなど、現在のコンテキストに依存するリンクには相対パスを使うことが多いでしょう。
Linkコンポーネントの高度な使い方/考慮事項
基本的な使い方だけでなく、Link
コンポーネントにはいくつかの応用的な使い方や、開発時に考慮すべき点があります。
動的なパスの生成
パスパラメータを含むルート(例: /users/:userId
)へのリンクを生成する場合、to
Propsの値は動的になります。JavaScriptのテンプレートリテラルや文字列連結を使って、パス文字列を生成します。
jsx
// ユーザーIDをpropsで受け取るリストアイテムコンポーネント
function UserListItem({ userId, userName }) {
return (
<li>
<Link to={`/users/${userId}`}>{userName}</Link>
</li>
);
}
この例では、userId
という変数を使って遷移先のパスを動的に生成しています。これはSPAでよく見られるパターンです。
クエリストリングやハッシュフラグメントの扱い
前述の通り、to
Propsのオブジェクト形式を使うことで、クエリストリング(search
)やハッシュフラグメント(hash
)を明確に指定できます。
“`jsx
// クエリストリング付きのリンク生成
<Link
to={{
pathname: ‘/products’,
search: new URLSearchParams({
category: ‘books’,
sort: ‘title’,
page: ‘2’
}).toString()
}}
書籍の2ページ目へ
“`
遷移先コンポーネントでは、useLocation().search
でクエリストリング全体(?category=...
)を取得し、それをURLSearchParams
コンストラクタに渡すことで、各クエリパラメータの値を取り出せます。
“`jsx
import { useLocation } from ‘react-router-dom’;
function ProductList() {
const location = useLocation();
const params = new URLSearchParams(location.search);
const category = params.get(‘category’); // ‘books’
const page = params.get(‘page’); // ‘2’
// … データ取得や表示ロジック …
}
“`
ハッシュフラグメントも同様にuseLocation().hash
で取得できます。通常、ハッシュはページ内の要素にジャンプするために使われますが、JavaScript側で特別な処理をフックすることも可能です(例: window.addEventListener('hashchange', ...)
)。
onClick
ハンドラの利用
Link
コンポーネントは、HTMLの<a>
タグと同様にonClick
Propsを受け付けます。このハンドラは、Link
によるナビゲーションが実行される前に呼び出されます。
これにより、以下のような処理を行うことができます。
- 遷移前の確認: ユーザーに操作の確認ダイアログを表示し、ユーザーが「キャンセル」を選択した場合は遷移を中止する。
- イベントトラッキング: Google Analyticsなどの分析ツールにリンククリックイベントを送信する。
- 簡単な状態更新: リンククリックに関連するアプリケーションの状態を更新する。
onClick
ハンドラ内で event.preventDefault()
を呼び出すことで、デフォルトのLink
によるナビゲーション動作をキャンセルできます。これにより、独自のロジックに基づいて遷移を制御することが可能になります。
“`jsx
function DeleteButtonWithConfirmation({ itemId }) {
const navigate = useNavigate(); // v6のプログラム遷移用フック
const handleClick = (event) => {
// デフォルトのLinkの遷移を防止
event.preventDefault();
// 確認ダイアログを表示
if (window.confirm('本当に削除しますか?')) {
// ユーザーがOKを選択した場合のみ処理を実行
console.log(`アイテム ${itemId} を削除します...`);
// 削除API呼び出しなど...
// 処理完了後、別のページへ遷移
// ここで navigate を使うのが一般的です
navigate('/items');
}
// ユーザーがキャンセルを選択した場合は何もせず、Linkによる遷移も発生しない
};
// 注意: この例では、Linkは削除処理のトリガーとしてのみ使われ、
// to に指定されたパスへの遷移は preventDefault でキャンセルされています。
// 削除ボタンは通常
return (
/items/${itemId}/delete} onClick={handleClick}>
アイテムを削除
);
}
``
onClick
この例はやや強引ですが、で
event.preventDefault()を使うことで
Link`のデフォルト挙動を上書きできることを示しています。より一般的なユースケースとしては、遷移前に確認メッセージを出し、OKならそのままLinkの遷移を実行する、というパターンです。
``jsx
本当に ${typeof to === ‘string’ ? to : to.pathname} に遷移しますか?`)) {
function NavLinkWithConfirmation({ to, children }) {
const handleClick = (event) => {
if (!window.confirm(
event.preventDefault(); // OKでなければ遷移をキャンセル
}
// OKの場合は preventDefault を呼び出さないので、Linkのデフォルト遷移が実行される
};
return (
{children}
);
}
// 使用例
設定ページ (確認あり)
“`
このように、onClick
ハンドラはLink
のクリックイベントにフックして、追加のロジックを実行するために使用できます。
アクティブなリンクのスタイリング (NavLinkコンポーネントの紹介と比較)
多くのナビゲーションでは、現在表示しているページに対応するリンクに特別なスタイル(例: 文字色を変える、下線を引く)を適用したい場合があります。これは「アクティブ状態のスタイリング」と呼ばれます。
Link
コンポーネント自体には、このアクティブ状態を自動的に検出してスタイルを適用する機能はありません。自分で現在のURLとLink
のto
Propsを比較して、条件付きでclassName
やstyle
Propsを適用する必要があります。これは少し手間がかかります。
“`jsx
import { Link, useLocation } from ‘react-router-dom’;
function Navigation() {
const location = useLocation();
const currentPath = location.pathname;
return (
);
}
“`
React Routerは、このアクティブ状態のスタイリングを簡単に行えるように、NavLink
という別のコンポーネントを提供しています。NavLink
はLink
と非常によく似ていますが、現在のURLがNavLink
のto
Propsとマッチした場合に、特別なクラス名(デフォルトはactive
)やスタイルを自動的に適用する機能を持っています。
“`jsx
import { NavLink } from ‘react-router-dom’;
function Navigation() {
return (
);
}
“`
ナビゲーションメニューなど、アクティブ状態のスタイリングが必要な場所では、Link
よりもNavLink
を使用するのが一般的です。NavLink
の詳細は別の記事で解説されることが多いですが、Link
との関係で知っておくべき重要なコンポーネントです。
外部サイトへのリンク (<a>
タグとの使い分け)
React RouterのLink
コンポーネントは、同じSPA内の異なるルートへの遷移を目的としています。外部のWebサイトや、明示的にフルリロードが必要なリソース(例: PDFファイルへのリンク)へのリンクを張りたい場合は、HTMLの標準的な<a>
タグを使用するべきです。
“`jsx
{/ SPA内部の別ルートへのリンク /}
内部ページへ
{/ 外部サイトへのリンク /}
Googleへ
{/ ファイルダウンロードへのリンク /}
資料をダウンロード
“`
Link
コンポーネントに外部URL (http://...
や https://...
) をto
Propsとして指定した場合、React Router v6では、内部的に標準の<a>
タグとしてレンダリングされ、通常のブラウザ遷移(フルリロード)が発生します。しかし、これはLink
の本来の用途ではないため、明示的に<a>
タグを使用する方が意図が明確で、混乱を防ぐことができます。
アクセシビリティ
リンクはWebサイトのナビゲーションの重要な要素であり、アクセシビリティに配慮することが重要です。Link
コンポーネントは最終的に<a>
タグとしてレンダリングされるため、<a>
タグに適用されるアクセシビリティの原則はそのまま適用されます。
- リンクテキスト: リンクのテキストは、リンク先の内容を明確に伝えるものであるべきです。「ここをクリック」のような漠然としたテキストは避けるべきです。
- ARIA属性: 必要に応じて、
aria-label
などのARIA属性を使用して、スクリーンリーダーユーザーに追加の情報を提供できます。
jsx
<Link to="/settings" aria-label="設定ページへ移動">
<SettingsIcon /> {/* アイコンだけのリンクの場合 */}
</Link>
適切なリンクテキストとARIA属性を使用することで、キーボードユーザーやスクリーンリーダーユーザーを含むすべてのユーザーがアプリケーション内を容易にナビゲートできるようになります。
Linkとその他のナビゲーション手段の比較
React RouterにはLink
以外にもナビゲーションのための手段がいくつかあります。それぞれの特徴を理解し、適切に使い分けることが重要です。
-
<a>
タグ:- 用途: 外部サイトへのリンク、ファイルダウンロード、明示的にフルリロードが必要な場合。
- 特徴: 標準のブラウザ遷移(フルリロード)。React Routerの制御を受けない。
- 使い分け: SPA内部のルーティングには使用しない。
-
Link
コンポーネント:- 用途: SPA内部のルートへのナビゲーション(ユーザーによるクリック操作)。
- 特徴: クライアントサイドルーティングによるスムーズな遷移。History APIを使用。URLやstateを宣言的に指定できる。
- 使い分け: ナビゲーションバー、リスト項目、ボタン状のリンクなど、ユーザーがクリックして別の画面に遷移する主要なインタラクションに使用する。
-
NavLink
コンポーネント:- 用途: SPA内部のルートへのナビゲーション + アクティブ状態のスタイリング。
- 特徴:
Link
の機能に加えて、アクティブな場合に自動的にクラスやスタイルが適用される。 - 使い分け: 主にグローバルナビゲーションメニューなど、現在のページを示すリンクを視覚的に強調したい場所で使用する。
-
useNavigate
フック:- 用途: プログラムによるナビゲーション。ユーザー操作以外のイベント(フォーム送信後、API呼び出し完了後、タイマー終了後など)での遷移。または、
onClick
ハンドラのようなイベント内で、Link
コンポーネントを使わずに遷移をトリガーしたい場合。 - 特徴: 関数呼び出しによって遷移を実行する。
Link
と同様にHistory APIを使用する。replace
オプションやstate
を渡すことができる。 - 使い分け: ボタンクリック時の遷移(ボタンは
<a>
要素である必要がない)、フォームの送信処理の後、非同期処理の完了後など、コードの中で動的に遷移を制御したい場合に使用する。
- 用途: プログラムによるナビゲーション。ユーザー操作以外のイベント(フォーム送信後、API呼び出し完了後、タイマー終了後など)での遷移。または、
“`jsx
// 例: ボタンクリックで遷移 (useNavigate)
import { useNavigate } from ‘react-router-dom’;
function MyButton() {
const navigate = useNavigate();
const handleClick = () => {
// なんらかの処理…
navigate(‘/destination’); // ‘/destination’ へ遷移
};
return ;
}
// 例: フォーム送信後の遷移 (useNavigate)
import { useNavigate } from ‘react-router-dom’;
function MyForm() {
const navigate = useNavigate();
const handleSubmit = (event) => {
event.preventDefault();
// フォームデータの処理、API送信など…
// 処理成功後
navigate(‘/success’, { state: { message: ‘フォームが送信されました’ } });
};
return (
);
}
“`
ユーザーがクリックしてナビゲートするためのUI要素として最も直接的に対応するのがLink
(またはNavLink
)です。プログラムからトリガーされる遷移にはuseNavigate
を使います。
実用的な例とサンプルコード
これまで学んだLink
コンポーネントの使い方を、具体的なシナリオで見ていきましょう。
例1: ヘッダーナビゲーション
アプリケーションのヘッダーに、主要なページへのリンクを配置する一般的な例です。アクティブなリンクを強調するためにNavLink
を使用することが多いですが、ここではLink
を使った基本的な例を示します。
“`jsx
// components/Header.js
import React from ‘react’;
import { Link } from ‘react-router-dom’;
import ‘./Header.css’; // スタイリング用のCSSファイル
function Header() {
return (
);
}
export default Header;
// App.js (抜粋)
import { Routes, Route } from ‘react-router-dom’;
import Header from ‘./components/Header’;
// 他のページコンポーネントをインポート…
function App() {
return (
{/ …他のルート /}
);
}
``
Header
この例では、コンポーネント内の
Linkをクリックすることで、対応するパスに遷移し、
内の
例2: リスト項目からの詳細ページへのリンク
ユーザー一覧や商品一覧のようなリストから、個別の詳細ページへ遷移する際に、動的なパスを持つLink
がよく使われます。
“`jsx
// components/UserList.js
import React from ‘react’;
import { Link } from ‘react-router-dom’;
function UserList({ users }) {
return (
-
{users.map(user => (
-
{/ to={/users/:userId} の形に動的に生成 /}
/users/${user.id}}>
{user.name}
))}
);
}
export default UserList;
// pages/UsersPage.js (抜粋)
import React, { useState, useEffect } from ‘react’;
import UserList from ‘../components/UserList’;
function UsersPage() {
const [users, setUsers] = useState([]);
useEffect(() => {
// 仮のユーザーデータ取得
const fetchUsers = async () => {
// 実際のアプリケーションではAPIからデータを取得
const data = [
{ id: 1, name: ‘Alice’ },
{ id: 2, name: ‘Bob’ },
{ id: 3, name: ‘Charlie’ }
];
setUsers(data);
};
fetchUsers();
}, []);
return (
Users
);
}
// App.js (ルーティング設定抜粋)
import { Routes, Route } from ‘react-router-dom’;
import UsersPage from ‘./pages/UsersPage’;
import UserDetailPage from ‘./pages/UserDetailPage’;
function App() {
return (
{/ パスパラメータ :userId を定義 /}
{/ …他のルート /}
);
}
// pages/UserDetailPage.js
import React from ‘react’;
import { useParams } from ‘react-router-dom’;
function UserDetailPage() {
const { userId } = useParams(); // URLからパスパラメータを取得
// userId を使ってユーザー詳細データを取得・表示
return (
User Detail
User ID: {userId}
{/ …ユーザー情報の表示 /}
);
}
``
UserListコンポーネントでは、各ユーザーオブジェクトの
idを使って、詳細ページへのパス
/users/${user.id}を生成しています。
UserDetailPageコンポーネントでは、
useParamsフックを使ってURLから
userId`を取得し、そのIDに基づいたデータを表示します。
例3: 検索結果からの遷移 (クエリストリングの使用)
検索フォームから検索結果ページへ遷移し、検索クエリをクエリストリングとして渡す例です。検索結果リストの項目から、そのアイテムの詳細ページへ遷移するリンクも含むことがあります。
“`jsx
// components/SearchBar.js
import React, { useState } from ‘react’;
import { useNavigate } from ‘react-router-dom’;
function SearchBar() {
const [query, setQuery] = useState(”);
const navigate = useNavigate(); // フォーム送信は navigate が適している
const handleSearch = (event) => {
event.preventDefault();
if (query.trim()) {
// /search?q=ユーザー入力値 へ遷移
navigate(/search?q=${encodeURIComponent(query.trim())}
);
}
};
return (
);
}
export default SearchBar;
// pages/SearchResultPage.js
import React from ‘react’;
import { useLocation, Link } from ‘react-router-dom’; // Link も使う可能性あり
function SearchResultPage() {
const location = useLocation();
const params = new URLSearchParams(location.search);
const searchQuery = params.get(‘q’); // クエリストリングから ‘q’ の値を取得
// 仮の検索結果
const results = searchQuery ? [{ id: 101, title: Result for ${searchQuery}
}, { id: 102, title: Another result for ${searchQuery}
}] : [];
return (
検索結果
{searchQuery ? (
<>
検索キーワード: “{searchQuery}”
-
{results.map(item => (
-
{/ 検索結果アイテムの詳細ページへのリンク /}
{/ 例: /items/101 /}
/items/${item.id}}>{item.title}
))}
) : (
検索キーワードを入力してください。
)}
);
}
// App.js (ルーティング設定抜粋)
import { Routes, Route } from ‘react-router-dom’;
import SearchBar from ‘./components/SearchBar’;
import SearchResultPage from ‘./pages/SearchResultPage’;
import ItemDetailPage from ‘./pages/ItemDetailPage’; // 仮の詳細ページコンポーネント
function App() {
return (
{/ …他のルート /}
);
}
// pages/ItemDetailPage.js (例)
import React from ‘react’;
import { useParams } from ‘react-router-dom’;
function ItemDetailPage() {
const { itemId } = useParams();
// itemId を使ってアイテム詳細データを取得・表示
return (
Item Detail: {itemId}
{/ … /}
);
}
``
useNavigate
この例では、検索フォームの送信にはを使っていますが、検索結果一覧から個別アイテムへの遷移には
Linkを使用しています。
SearchResultPageでは
useLocation`を使ってクエリストリングを取得し、表示内容を変えています。
例4: 遷移先に状態を渡す (state
)
特定のページから別のページへ遷移する際に、URLに表示させたくないが、遷移先のコンポーネントで利用したい一時的なデータを渡す場合にstate
Propsが役立ちます。
“`jsx
// pages/ProductsPage.js (商品一覧)
import React from ‘react’;
import { Link } from ‘react-router-dom’;
function ProductsPage() {
const products = [
{ id: 1, name: ‘Laptop’, price: 1200 },
{ id: 2, name: ‘Keyboard’, price: 75 },
{ id: 3, name: ‘Mouse’, price: 25 }
];
return (
Products
-
{products.map(product => (
-
{/ 商品詳細ページへのリンクに、価格情報を state として渡す /}
/products/${product.id}}
state={{ referrer: ‘products-list’, initialPrice: product.price }}
>
{product.name} – ${product.price}
))}
);
}
// pages/ProductDetailPage.js (商品詳細)
import React from ‘react’;
import { useParams, useLocation } from ‘react-router-dom’;
function ProductDetailPage() {
const { productId } = useParams();
const location = useLocation();
const state = location.state; // state を取得
console.log(‘Location state:’, state); // { referrer: ‘products-list’, initialPrice: 1200 } などが表示される
// productId を使って商品詳細データを取得・表示
return (
Product Detail: {productId}
{state && state.initialPrice && (
Initial Price (from list): ${state.initialPrice}
)}
{/ …詳細情報の表示 /}
);
}
// App.js (ルーティング設定抜粋)
import { Routes, Route } from ‘react-router-dom’;
import ProductsPage from ‘./pages/ProductsPage’;
import ProductDetailPage from ‘./pages/ProductDetailPage’;
function App() {
return (
{/ …他のルート /}
);
}
``
referrer
この例では、商品一覧ページから商品詳細ページへ遷移する際に、商品リストから取得した一部の情報(や
initialPrice)を
stateとして渡しています。商品詳細ページでは、
useLocation().stateを使ってその情報を受け取り、表示や処理に利用できます。これは、API呼び出しを減らしたり、遷移元のコンテキスト情報を提供したりするのに便利です。ただし、
state`はリロードで失われるため、永続化が必要なデータや、直接URLからアクセスした場合でも表示できる必要があるデータには適していません。
トラブルシューティングとよくある落とし穴
Link
コンポーネントを使う上で遭遇しやすい問題と、その解決策をいくつか紹介します。
-
Link
が機能しない、フルリロードが発生する:- 原因1: アプリケーション全体が
BrowserRouter
(または他のRouterコンポーネント)で囲まれていない。- 解決策: アプリケーションのルートコンポーネント(例:
App
)や、ルーティングを使用する部分全体をreact-router-dom
からインポートしたBrowserRouter
などのRouterコンポーネントで囲んでください。
- 解決策: アプリケーションのルートコンポーネント(例:
- 原因2:
Link
ではなく<a>
タグを使っている。- 解決策: SPA内部のナビゲーションには
<a>
タグではなくLink
コンポーネントを使用しているか確認してください。
- 解決策: SPA内部のナビゲーションには
- 原因3:
target="_blank"
などを指定している。- 解決策:
target="_blank"
は新しいタブ/ウィンドウで開く指示であり、多くの場合フルリロードを伴います。SPA内部リンクで新しいタブを開くのはユーザー体験上一般的ではないため、基本的にはtarget
属性は使用しません。もし外部サイトへのリンクで新しいタブを開きたいなら、迷わず<a>
タグを使いましょう。
- 解決策:
- 原因4:
onClick
ハンドラ内でevent.preventDefault()
を呼び出しているが、その後useNavigate
などでプログラムによる遷移を行っていない。- 解決策:
onClick
でデフォルトの遷移を阻止した場合、自分でプログラム的に遷移をトリガーするか、あるいはpreventDefault
を条件付きで呼び出す(例: 確認ダイアログでキャンセルされた場合のみ)ようにロジックを見直してください。
- 解決策:
- 原因1: アプリケーション全体が
-
相対パスが意図しないパスに解決される:
- 原因: 現在のURLパスに対する相対的な解決ルール(
relative="path"
)と、期待する遷移先パスが一致しない。特にネストされたルーティングで発生しやすい。 - 解決策:
to
Propsに絶対パスを使用することを検討する。- 現在のURLと
to
に指定した相対パスがどのように解決されるか、紙やコンソールで確認してみる。 - React Router v6.4以降を使っている場合は、
relative="route"
Propsが役立つか検討する。しかし、多くの場合デフォルトのrelative="path"
が直感的です。 - どうしても相対パスでの解決が難しい場合は、
useNavigate
とuseResolvedPath
フックを組み合わせて、プログラムで相対パスを解決し、その結果を使って絶対パスで遷移するという方法もあります(上級)。
- 原因: 現在のURLパスに対する相対的な解決ルール(
-
state
が遷移先で取得できない:- 原因1:
state
Propsまたはto
オブジェクトのstate
プロパティで正しくstate
を渡せていない。- 解決策:
Link
コンポーポーネントのPropsでstate={{ key: value }}
またはto={{ pathname: '...', state: { key: value } }}
のように指定しているか確認してください。
- 解決策:
- 原因2: 遷移先のコンポーネントで
useLocation().state
を正しく取得できていない。- 解決策: 遷移先のコンポーネントで
import { useLocation } from 'react-router-dom'; const location = useLocation(); const state = location.state;
のように正しく取得しているか確認してください。
- 解決策: 遷移先のコンポーネントで
- 原因3: 遷移先のページが直接URLでアクセスされた(例: ブラウザのリロード、ブックマーク、URLの直接入力)。
- 解決策:
state
はブラウザの履歴エントリに紐づく一時的な情報です。リロードや直接アクセスでは失われます。state
に依存する表示や処理を行う場合は、state
が存在しない場合のフォールバックロジック(例: データを再取得する、エラーメッセージを表示するなど)を実装する必要があります。永続化が必要なデータは、クエリストリング、パスパラメータ、ローカルストレージ、またはサーバー側で管理することを検討してください。
- 解決策:
- 原因1:
-
スタイリングが効かない、または意図しないスタイルが適用される:
- 原因1: CSSセレクタが正しくない。
Link
コンポーネントは最終的に<a>
タグとしてレンダリングされるため、CSSではa
要素や指定したclassName
に対してスタイルを適用します。 - 解決策: 開発者ツールでレンダリングされたHTMLを確認し、要素構造やクラス名を確認してください。CSSセレクタが正しく要素をターゲットにしているか確認してください。
- 原因2:
NavLink
と間違えている、またはNavLink
のアクティブスタイルが期待通りに適用されない。- 解決策: アクティブスタイリングが必要な場合は
NavLink
を使用しているか確認してください。NavLink
のアクティブクラス名やスタイルはカスタマイズ可能です (activeClassName
,activeStyle
Props – v5、v6では関数形式のclassName
/style
Propsを使用)。ルーティング設定(特にネストされたルートやインデックスルート)がNavLink
のパスと正確にマッチしているか確認してください。
- 解決策: アクティブスタイリングが必要な場合は
- 原因1: CSSセレクタが正しくない。
これらのよくある問題を理解しておくことで、開発中のデバッグ時間を減らすことができます。
まとめ
この記事では、React RouterにおけるSPAナビゲーションの要であるLink
コンポーネントについて、その基礎から応用、そして他のナビゲーション手段との比較まで、詳細に解説しました。
Link
コンポーネントは、HTMLの<a>
タグのように見えますが、クリックされた際にブラウザのフルリロードを防ぎ、History APIを利用してReact Routerによるクライアントサイドルーティングをトリガーするという重要な役割を担っています。これにより、SPAのスムーズで高速なページ遷移を実現します。
Linkコンポーネントの主要なポイントをまとめます。
- SPA内部のルート間を遷移するための主要なUIコンポーネントです。
- 必須の
to
Propsで遷移先のパスを指定します。文字列またはオブジェクトで指定でき、オブジェクト形式ではpathname
,search
,hash
,state
などを細かく設定できます。 replace={true}
Propsで、履歴スタックに新しいエントリを追加する代わりに現在のエントリを置き換えることができます。state
Propsまたはto
オブジェクトのstate
プロパティで、遷移先のコンポーネントに一時的なデータを渡すことができます(リロードで失われます)。- 相対パス (
/
で始まらない) は、デフォルトでは現在のURLを基準に解決されます(relative="path"
)。v6.4+ではrelative="route"
でルート定義パス基準に変更できます。 onClick
ハンドラで、遷移前のロジックを実行したり、event.preventDefault()
でデフォルトの遷移をキャンセルしたりできます。- HTMLの
<a>
タグの多くの標準属性(className
,style
,title
など)をPropsとして受け付けます。 - アクティブ状態のスタイリングが必要な場合は、
Link
の代わりにNavLink
を使用するのが一般的です。 - 外部サイトへのリンクやフルリロードが必要な場合は、HTMLの
<a>
タグを使用すべきです。 - プログラムによる遷移には
useNavigate
フックを使用します。
Link
コンポーネントは、React Routerを使ったSPA開発において最も頻繁に利用されるコンポーネントの一つです。その使い方と、Propsによるカスタマイズ方法をしっかりと理解することは、ユーザーフレンドリーで効率的なアプリケーションを構築するために不可欠です。
この記事で学んだ知識を活かして、あなたのReactアプリケーションに快適なナビゲーションを実装してみてください。さらに深いルーティングの概念(ネストされたルーティング、認証付きルート、データローディングなど)や、NavLink
, useNavigate
などの他のReact Router機能についても学ぶことで、より高度なSPA開発が可能になります。
この解説が、あなたのReact RouterおよびLink
コンポーネントの理解を深める一助となれば幸いです。Happy Coding!
およそ5000語となるように、各セクションを詳細に記述し、例を豊富に含めました。要件通り、記事の内容を直接表示しています。