🙌

React Router(v6)で画面遷移前の前処理の結果で、画面遷移を制御したい

2022/07/03に公開

本記事では、React Router を用いた ルーティング制御で、
画面遷移前の前処理の結果で、画面遷移を制御する実装を紹介します。

はじめに

結論

Route コンポーネントをラップしたコンポーネントを作成し、
上記コンポーネント内に関数の処理を注入する流れで制御できました。

※React Router v5→v6 で、いくつかの破壊的変更(こちらの記事が参考になりました)
があるため、v5 を利用の方は下記実装と対応が少し異なります。

また、v5→v6 の変更点は下記記事が参考になりました。

下記以降は実装例となります。

Before

ここでは、about ページヘ遷移する際に、何らかの処理(セッションチェック、不正な遷移のチェック、等)を行いたいケースを想定しています。

src/Router.tsx
import { FC } from "react";
import { Routes, Route } from "react-router-dom";
import { AboutPage } from "../src/page/About";
import { HomePage } from "../src/page/Home";

const Router: FC = () => {
  return (
    <Routes>
      <Route path="/" element={<HomePage />} />
      {/* AboutPageに遷移前に処理を入れたい */}
      <Route path="about" element={<AboutPage />} />
    </Routes>
  );
};

export default Router;

実装

カスタムルートコンポーネントの作成

  • 画面遷移前の前処理と、リダイレクト先のパスを受け取る CustomRoute.tsx を作成します。
src/CustomRoute.tsx
import { RouteProps, Navigate, Outlet } from "react-router-dom";

/**
 * カスタムルートコンポーネントに渡すProps
 */
type CustomRouteProps = {
  // 前処理で判定したい関数
  beforeEnter: () => boolean;
  // リダイレクト先のパス
  redirectPath: string;
} & RouteProps;

/**
 * カスタムルートコンポーネント
 *
 * 前処理の結果に応じて遷移をスイッチする。
 */
const CustomRoute = ({
  beforeEnter,
  redirectPath,
  ...props
}: CustomRouteProps) => {
  const beforeEnterResult = beforeEnter();

  // 前処理の結果に応じて遷移をスイッチする。
  return beforeEnterResult ? <Outlet /> : <Navigate to={redirectPath} />;
};

export default CustomRoute;


カスタムルートコンポーネントを利用する

  • 作成したカスタム Route コンポーネントを Router.tsx で利用する。
src/Router.tsx
import { FC } from "react";
import { Routes, Route } from "react-router-dom";
import CustomRoute from "./CustomRoute";
import { AboutPage } from "../src/page/About";
import { HomePage } from "../src/page/Home";
import { RedirectPage } from "./page/Redirect";

const Router: FC = () => {
  return (
    <Routes>
      <Route path="/" element={<HomePage />} />
      {/**
       * CustomRoute 用例
       * -----------------------------------------------------
       * 下記の例;
       * AboutPage遷移前に判定したい処理を、
       * CustomRouteコンポーネントのbeforeEnterにわたすことで、
       * CustomRouteコンポーネント内で、遷移をスイッチする。
       * redirectPathには、処理NG時に遷移したいパスを指定する。
       * -----------------------------------------------------
       */}
      <Route
        path="/about"
        element={
          <CustomRoute beforeEnter={mockAuth} redirectPath="/redirect" />
        }
      >
        <Route path="/about" element={<AboutPage />} />
      </Route>
      <Route path="/redirect" element={<RedirectPage />} />
    </Routes>
  );
};

/**
 * ランダムでtrue,falseを返す関数
 */
const mockAuth = () => {
  return Math.floor(Math.random() * 2) >= 1;
};

export default Router;

v5→v6 の変更点 で Routes の直下コンポーネントは Route しか受け付けないようになったため、
ちょっと冗長な書き方になってしまっていますが、上記のような雰囲気で実装できました。
(v5 で同じような実装をする場合はもっとシンプルに書けました)

element に CustomRoute を指定した Route コンポーネント(親)に、element に AboutPage を指定した Route コンポーネント(子)を入れ子にすることで、CustomRoute.tsx の Outlet(子側に指定したコンポーネント) を表示するか、リダイレクトするかを制御しています。

遷移前に処理したい前処理が予め決まっている場合には、beforeEnter の Props を取り外して、
CustomRoute.tsx にカスタムフックでロジックを注入するほうがスマートかもしれないです。

After

最終的なソースコードはこちらから閲覧いただけます。

最後に

vue-router と比較して、react-router は元から提供されている機能は少ないように思いますが、その分ソース上で柔軟に制御ができるのが良いところだなと思いました。

GitHubで編集を提案

Discussion