Reactルーティングを理解してスムーズなSPAを実現する方法

はじめに

Reactを使った開発では、ページ遷移をどう実装するかが大きなテーマになります。 特に、複数の画面やページを持つアプリケーションを作る場合は、ユーザーがスムーズに移動できる仕組みが必須でしょう。 そこで登場するのがReactルーティングです。 シングルページアプリケーション(SPA)であるにもかかわらず、URLごとに異なる画面を表示しているように見せることができます。 実務でもほとんどの場合、何らかの形でルーティングが行われているため、理解しておくと開発の幅が一気に広がるはずです。

この記事を読むとわかること

  • Reactルーティングの基本的な仕組み
  • ルーティングの実務での活用イメージ
  • 実装の具体例やコードの書き方
  • ネストされたルーティングやリダイレクトの方法
  • ルーティングとSEOの関係性
  • トラブルシューティングのポイント

Reactルーティングとは

Reactルーティングとは、ブラウザのURLに応じて表示するコンポーネントを切り替える仕組みです。 通常、複数のHTMLファイルでページ遷移を行う場合はサーバーが各HTMLを返しますが、Reactの場合はひとつのHTMLを起点にJavaScriptで画面を動的に切り替えます。 この動的な切り替えをわかりやすく整理してくれるのが、ルーティングライブラリです。 代表的な例としてreact-router-domを利用することが多いでしょう。 実務でも、SPAであっても複数のページを扱いたいときに必須の機能なので、まずは基本をしっかり理解しておくと安心ですね。

ルーティングの基本構成

Reactでルーティングを実現するには、まずルーターコンポーネントが必要です。 最もシンプルな形では、アプリ全体を<BrowserRouter>で包み込み、その内部で<Routes><Route>を定義します。 ルートパスに対応するコンポーネントを設定するイメージで、ユーザーのアクセス先が変わると表示されるコンポーネントが変わります。 開発時には、ファイルやフォルダを画面ごとに分けることが多いので、どのURLでどのコンポーネントを表示するかを見通しよく整理すると良いでしょう。 社内システムや顧客向けの管理画面など、複数ページ構成のアプリケーションに向いています。

ルーティングが必要になる実務シーン

ルーティングの主な利用シーンは、情報量が多くページを分割して管理したい場合です。 例えば、ECサイトの商品一覧ページや商品詳細ページ、カートページなどをReactで開発するときに、URLのパラメータに応じた画面切り替えが行われます。 また、管理者画面やダッシュボードなどでも、複数のメニューをそれぞれ別ルートとして扱うケースが多いでしょう。 URLの構造をわかりやすく設計しておくと、ユーザーがブラウザの戻る/進むボタンを使ったり、URLを直接入力しても狙い通りのページが表示されます。 これらはユーザー体験を損ねないためにも重要なポイントです。

ルーティング構成は初期の段階でしっかり計画し、画面数が増えても拡張しやすいようにしておくと安心です。

基本的なルーティングの実装例

実装イメージをつかむには、まず最小限のコード例を見てみると理解しやすいです。 以下はreact-router-domを使った簡単なサンプルです。

import React from "react";
import { BrowserRouter, Routes, Route } from "react-router-dom";
import Home from "./pages/Home";
import About from "./pages/About";

function App() {
  return (
    <BrowserRouter>
      <Routes>
        <Route path="/" element={<Home />} />
        <Route path="/about" element={<About />} />
      </Routes>
    </BrowserRouter>
  );
}

export default App;

<BrowserRouter>が全体を包み込み、<Routes>の中に<Route>を複数定義する形です。 path="/"に対しては<Home>コンポーネントが、path="/about"に対しては<About>コンポーネントが表示されます。 これだけで、URLが"/"のときにトップページ、"/about"のときにアバウトページを表示できるわけです。 アプリが大きくなっても同じ考え方でルートを追加していけばOKなので、構造がシンプルで把握しやすいでしょう。

ルーティングとリンクの関係

Reactルーティングでは、URLの書き換えやブラウザ履歴の管理をJavaScriptが行います。 ページ遷移のためには、<a>タグを直接書くのではなく、react-router-domが提供する<Link>コンポーネントを使うのが一般的です。

import { Link } from "react-router-dom";

function Navigation() {
  return (
    <nav>
      <Link to="/">トップ</Link>
      <Link to="/about">アバウト</Link>
    </nav>
  );
}

export default Navigation;

<Link>を使うことでブラウザの履歴に正しく対応し、余計なページリロードも発生しません。 動作的にはSPAらしくスムーズな画面切り替えが行われるため、ユーザーの操作感も向上するはずです。 メニューやヘッダーなどに<Link>を設定しておけば、多くの画面を横断的に操作できるようになるでしょう。

動的パラメータの扱い方

実務では、URLの一部をパラメータとして受け取り、特定のデータを表示したいケースが頻繁に発生します。 例えば、ユーザーのプロフィールページを表示するときなどです。 その場合は、ルート定義で/users/:userIdのように記述し、:userIdの部分をパラメータとして扱います。 実際のURLが/users/10であれば、コンポーネント側でuserIdを10として取得できるイメージです。

動的パラメータを使った実装例

以下のサンプルではユーザーIDに応じて表示を切り替える構成を示しています。

import { BrowserRouter, Routes, Route } from "react-router-dom";
import Users from "./pages/Users";
import UserDetail from "./pages/UserDetail";

function App() {
  return (
    <BrowserRouter>
      <Routes>
        <Route path="/users" element={<Users />} />
        <Route path="/users/:userId" element={<UserDetail />} />
      </Routes>
    </BrowserRouter>
  );
}

export default App;

UserDetailコンポーネントの中では、useParams()を使ってURLパラメータを取得します。

import { useParams } from "react-router-dom";

function UserDetail() {
  const { userId } = useParams();

  return (
    <div>
      <h1>ユーザーID: {userId}</h1>
      {/* ここでuserIdをもとにAPIを呼び出して情報を取得・表示するなど */}
    </div>
  );
}

export default UserDetail;

実務上も、このようにURLの一部にIDやスラッグを含めることで、ユーザーごとの詳細画面や商品ごとのページをシンプルに作成できます。 URLとコンポーネントが一対一に対応する形なので、管理がしやすいことも特徴です。

ネストされたルーティング

大規模なアプリケーションでは、ページ階層を深く設定したいケースもあります。 例えば/users以下にユーザー一覧とユーザー詳細をまとめるようにしたいときです。 このようなときには、ルート定義をネストして指定します。

ネストルーティングのコード例

import { BrowserRouter, Routes, Route } from "react-router-dom";
import Home from "./pages/Home";
import Users from "./pages/Users";
import UserDetail from "./pages/UserDetail";

function App() {
  return (
    <BrowserRouter>
      <Routes>
        <Route path="/" element={<Home />} />
        <Route path="/users" element={<Users />}>
          <Route path=":userId" element={<UserDetail />} />
        </Route>
      </Routes>
    </BrowserRouter>
  );
}

export default App;

このように親ルートとして/usersを設定し、その中にさらに/:userIdを定義するスタイルです。 実務では一覧ページや設定ページ、サブメニューなどをまとめておくのにも便利でしょう。 ユーザーから見れば自然なURL設計になりますし、関連ページをグルーピングできるため、管理しやすくなります。

クエリ文字列の扱い

ECサイトで検索結果にフィルターをかけたり、ソート順を指定したりするとき、クエリ文字列を利用することがあります。 ?sort=asc?category=shoesのような形です。 Reactルーティング自体ではクエリ文字列をパラメータとして扱いませんが、JavaScriptのURLSearchParamsを利用すると取得が簡単です。 コンポーネント内でconst params = new URLSearchParams(location.search);のように書き、パラメータの値を取得できます。 また、必要に応じて状態管理ライブラリと組み合わせることで複雑な検索条件にも対応できるでしょう。

クエリ文字列が増えすぎるとURLが長くなり、ユーザーから見にくくなる場合があります。 整理しながら使うことをおすすめします。

リダイレクトと認証

ユーザーが特定のページを閲覧する前にログインを求めたい場面もあります。 ログインしていない場合はログインページへリダイレクト、という動きは実務でもよくあるパターンでしょう。 react-router-domでは、認証状態をチェックし、条件に合わなければ特定のページへ誘導する仕組みが作れます。 以下のようにガード機能を実装する例があります。

import { Navigate } from "react-router-dom";

function PrivateRoute({ children }) {
  const isLoggedIn = false; // 例: ログイン状態を管理する変数

  if (!isLoggedIn) {
    return <Navigate to="/login" />;
  }

  return children;
}

export default PrivateRoute;

上記を使えば、特定のルートをガードしてログイン画面に飛ばすことができるため、セキュリティ面でも役立つでしょう。

ルーティングとコード分割

大きなアプリケーションになってくると、初回読み込みを少しでも軽くするためにコード分割を行うケースがあります。 ReactではReact.lazySuspenseを活用して、ルートごとにコンポーネントを遅延読み込みすることができます。 例えば/usersを最初から読み込まずに、必要になったときに取得する仕組みが構築可能です。 これにより、ユーザーが実際にアクセスするまで読み込まないので、アプリ全体のパフォーマンスが向上しやすいです。 一度ロードしたコンポーネントはキャッシュされるため、次回以降の読み込みもスムーズになります。

ルーティングとSEOの関係性

シングルページアプリケーションの場合、ルーティングによって動的にコンテンツを切り替えます。 ただし、ブラウザが内容を生成しているだけなので、検索エンジンに正しく認識されるかが気になる方もいるでしょう。 実際のところ、クローラーがJavaScriptをある程度実行できるようになってきていますが、SSR(サーバーサイドレンダリング)などを考慮するケースもあります。 しかし、Reactルーティングが直接SEOを損ねるわけではありません。 適切にメタタグを用意し、クローラーがアクセスできるリンク構造を作ることが大切です。 もしSSRなどを検討するなら、Next.jsのようにルーティングとSSRを同時に管理するフレームワークを選ぶ手段もあります。

ルーティングエラー画面の設計

存在しないURLにアクセスした場合や、想定外のパラメータが指定された場合には、ユーザーにエラー画面を表示するのが一般的です。 404ページなどがそれにあたります。 react-router-domでは、定義されていないパスへアクセスされた際に404用のルートを最後に用意しておくことが多いです。 特にSPAの場合、ユーザーがURLを直接打ち込んで来る可能性があるので、見やすいエラーメッセージを出すとユーザーに安心感を与えられるでしょう。

404ページの簡易実装例

function NotFound() {
  return (
    <div>
      <h2>ページが見つかりません</h2>
      <p>URLが誤っているか、ページが移動した可能性があります。</p>
    </div>
  );
}

export default NotFound;

<Routes>内で最下部に<Route path="*" element={<NotFound />} />のように定義すると、どこにもマッチしない場合に表示できます。 エラー画面に戻るボタンやトップページへのリンクを設置しておくと、ユーザーが迷わずに次の行動に移れるはずです。

まとめ

Reactルーティングは、シングルページアプリケーションで複数ページを扱うために欠かせない仕組みです。 URLに応じてコンポーネントを切り替えるだけでなく、認証が必要なページのガードやネスト構造、コード分割など、実務を想定するとさまざまな活用方法があります。 最初は基本的なルート定義から始め、要件に合わせて動的パラメータやリダイレクトを追加していくと段階的に理解しやすいでしょう。 初心者の皆さんがReactルーティングをマスターし、スムーズなページ遷移を実装できるよう願っています。 実際の開発では画面数が増えるほどルーティングの設定も複雑になりやすいので、ディレクトリ構成やURL設計を最初にしっかり検討してみてください。 そうすれば、より拡張性の高いアプリケーションを効率よく作り上げられるのではないでしょうか。

Reactをマスターしよう

この記事で学んだReactの知識をさらに伸ばしませんか?
Udemyには、現場ですぐ使えるスキルを身につけられる実践的な講座が揃っています。