ルーティングの基本設定

2024.07.10

SPA(シングルページアプリケーション)で必要となるのがルーティング機能。

SPAを利用するにはどのURLにどのコンポーネントを割り当てるかなどのルーティングの指定が必要です。この記事ではルーティングの設定方法とグローバルナビゲーションやルートパラメータの設定方法を記載します。

とりあえず、「こうすると動く!」という感じにざっくり書いていきます。
細かく書くと記事の量が膨大になりそうだったので…

「react-router-dom」のインストール

ルーティング機能はプロジェクト作成時は組み込まれていないためインストールする必要があります。
まずは「react-router-dom」をインストールします。

npm install react-router-dom

ルーティングの設定をし、各ページを表示する。

プロジェクトのsrc内にルーティングを設定するtsxファイルを作成します。今回はroutesLink.tsxというファイル名にしています。下記がそのコードです。

import { Route, createBrowserRouter, createRoutesFromElements } from 'react-router-dom';
import TopPage from './pages/TopPage';//トップページのコンポーネント
import TestPage from './pages/TestPage';//テストページのコンポーネント
import RouterNav from './components/header/RouterNav';//共通ナビゲーション

const routesLink = createBrowserRouter(
  createRoutesFromElements(
    <Route element={<RouterNav />}>//共通ナビゲーション
      <Route path="/" element={<TopPage />} />
      <Route path="/test" element={<TestPage />} />
    </Route>
  )
);

export default routesLink;

コンポーネントと各ページURLへの紐付け

先ほどのコンポーネントの詳細説明です。
コンポーネント情報をインポートし、それぞれのコンポーネントにページURLを割り当てています。
ページを割り振るコンポーネントは「~/page/」の中に設置しています。

//コンポーネントのインポート
import TopPage from './pages/TopPage';
import TestPage from './pages/TestPage';

~~~~~~~~~略~~~~~~~~~~~
~~~~~~~~~略~~~~~~~~~~~

//TopPageコンポーネントにドメイン直下のルートを割り当てています。
<Route path="/" element={<TopPage />} />

//TestPageコンポーネントに「/test」のルートを割り当てています。
<Route path="/test" element={<TestPage />} />

~~~~~~~~~略~~~~~~~~~~~

アプリの基点となるindex.tsxやmain.tsxにルーティング定義をインポート

Reactインストール時にあるindex.tsxファイルに定義したルーティングをインポートします。

import React from 'react'
import ReactDOM from 'react-dom/client'
import { RouterProvider }  from 'react-router-dom';
import routesLink from './routesLink';//定義したルーティングの読み込み
import './index.scss'

ReactDOM.createRoot(document.getElementById('root')!).render(
  <React.StrictMode>
    <RouterProvider router={routesLink} />
  </React.StrictMode>,
)

ここで重要なのは下記の部分ですね。

~~~~~~~~~略~~~~~~~~~~~

import { RouterProvider }  from 'react-router-dom';
import routesLink from './routesLink';//定義したルーティングの読み込み

~~~~~~~~~略~~~~~~~~~~~

<RouterProvider router={routesLink} />

~~~~~~~~~略~~~~~~~~~~~

これで大枠は完成です。

//設定したルート定義(routesLink)をrouterに渡しています
<RouterProvider router={routesLink} />

RouterProviderにより配下のコンポーネント全てがReactRouterの管理化になりルーティングがきくようになります。

ここまですると「/(ドメイン直下)」に設定したTopPageコンポーネントの内容が表示されます。

また、ブラウザurl欄に「~/test」を入力するとTestPageコンポーネントの内容が表示されます。

共通ナビゲーション(NavLink)について

ルーティングを定義した内容に戻ります。
この中にRouterNavという部分がありますが、これがどのページでも表示され共通ナビゲーションです。

import { Route, createBrowserRouter, createRoutesFromElements } from 'react-router-dom';
import TopPage from './pages/TopPage';//トップページのコンポーネント
import TestPage from './pages/TestPage';//テストページのコンポーネント
import RouterNav from './components/header/RouterNav';//共通ナビゲーション

const routesLink = createBrowserRouter(
  createRoutesFromElements(
    <Route element={<RouterNav />}>//共通ナビゲーション
      <Route path="/" element={<TopPage />} />
      <Route path="/test" element={<TestPage />} />
    </Route>
  )
);

export default routesLink;

RouterNavの中身は下記のようになります。ナビゲーションメニューに特化したNavLinkというのを使っています。

コンポーネント中身は下記になります。

import { NavLink, Outlet } from 'react-router-dom';


export default function RouterNav() {
  return (
    <>
      <header>
        <nav>
          <ul>
            <li><NavLink to="/" >トップ</NavLink></li>
            <li><NavLink to="/test" >TestPage</NavLink></li>
          </ul>
        </nav>
      </header>
      <Outlet />
    </>
  );
}

サイト上の共通ナビゲーションで使用します。このコンポーネントを読み込むとトップページでもテストページでもどのページでも表示がされるようになります。

NavLinkの便利な機能。現在開いてるページリンクに「active」クラスがつく

Webサイトを作ってると、現在表示してるページを視覚的にするためナビゲーションに下線をつけたりすることがあります。該当のリンク「Current」というクラス名をつけることで実装していました。

NavLinkにはデフォルトでこの機能がついています。例えばTestPageを開いてるときはactiveクラスがつきます。下記はブラウザ開発ツールで見た際の画像です

これは視覚的に現在のページであることを表しすのに便利ですね!

ちなみにaタグに付与されるクラス名を変えたい場合は下記のような記述をすれば、変更できます。

import { NavLink, Outlet } from 'react-router-dom';


const isCurrent = ({ isActive }: { isActive: boolean }) => isActive ? 'isCurrent' : '';

export default function RouterNav() {
  return (
    <>
      <header>
        <nav>
          <ul>
            <li><NavLink className={isCurrent} to="/" >トップ</NavLink></li>
            <li><NavLink className={isCurrent} to="/test" >TestPage</NavLink></li>
          </ul>
        </nav>
      </header>
      <Outlet />
    </>
  );
}

これによりリンクと合致するページの時はisCurrentクラスがつくようになります。

このように該当ページの時にactiveクラスがつくのは大変便利です。

ただ、下記のような場合は注意です。

import { NavLink, Outlet } from 'react-router-dom';


const isCurrent = ({ isActive }: { isActive: boolean }) => isActive ? 'isCurrent' : '';

export default function RouterNav() {
  return (
    <>
      <header>
        <nav>
          <ul>
            <li><NavLink className={isCurrent} to="/" >トップ</NavLink></li>
            <li><NavLink className={isCurrent} to="/test" >TestPage</NavLink></li>
            <li><NavLink className={isCurrent} to="/test/abcdef" >TestPage -abcdef-</NavLink></li>
          </ul>
        </nav>
      </header>
      <Outlet />
    </>
  );
}

この場合、「/test/abcdef」ページを開いてると「/test」「/test/abcdef」のリンク全てにactiveなクラスがついてしまいます。これを防ぐためには「/test」にend属性を付与すると防ぐことができます。

<li><NavLink className={isCurrent} to="/test" end >TestPage</NavLink></li>
<li><NavLink className={isCurrent} to="/test/abcdef" >TestPage -abcdef-</NavLink></li>

ルートパラメータ

次はルートパラメーターについて
例えば「/news」という記事一覧を表示するページがあるとします。この下のパスには記事ページへのリンクが入ります。

「/news/posttitle1」「/news/posttitle2」」「/news/posttitle3」….というふうに記事が増えるたびに「/news」配下にどんどん増えていきます。

これをルーティングで一個一個設定するのは現実的ではないです。そんな時に利用するのがルートパラメーターです。

ルーティングを設定しているファイルに以下のように記述します。

import { Route, createBrowserRouter, createRoutesFromElements } from 'react-router-dom';
import TopPage from './pages/TopPage';
import TestPage from './pages/TestPage';
import TestPageDetail from './pages/TestPageDetail';//ここがルートパラメータの際の表示するコンポーネント
import RouterNav from './components/header/RouterNav';

const routesLink = createBrowserRouter(
  createRoutesFromElements(
    <Route element={<RouterNav />}>
      <Route path="/" element={<TopPage />} />
      <Route path="/test" element={<TestPage />} />
      <Route path="/test/:id" element={<TestPageDetail />} />//ここがルートパラメータ
    </Route>
  )
);

export default routesLink;

「/test/:id」このようにすればルートパラメータとして働き、どんなURLにも対応して下層ページを表示することができます。

これをルートパラメーターで表示する場合は該当コンポーネントでパラメーターを受け取る必要があります。

コンポーネントでルートパラメーターを受け取る方法

ルートパラメーターを受け取るコンポーネント(今回の場合はTestPageDetail)にて「useParams」関数を使います。サンプルは下記です。

import { useParams } from 'react-router-dom';
import './styles.scss';


export default function TestPageDetail()  {
  const { id } = useParams<{ id: string }>();

  return (
    <>
      <div className='postContents'>
        <p>{ id }のページです</p>
      </div>
    </>
  );
};

このようにすることでブラウザURL欄のパラメーターを取得し、内容を表示することができます。

まとめ

ここまでがReactでよく使うルーティングの基本的な機能かなと思います。ルートパラメーターなどはAPIを取得して個別記事ページを作成するのにも利用できます。

totop Page Top