React Router(v6)で画面遷移前の前処理の結果で、画面遷移を制御したい
本記事では、React Router を用いた ルーティング制御で、
画面遷移前の前処理の結果で、画面遷移を制御する実装を紹介します。
はじめに
- Create React App で環境構築。
- 画面ルーティングに React Router(v6) を利用。
- Vue でいうナビゲーションガードのルート単位ガードのような機構を、React Router でも実現したい。
結論
Route コンポーネントをラップしたコンポーネントを作成し、
上記コンポーネント内に関数の処理を注入する流れで制御できました。
※React Router v5→v6 で、いくつかの破壊的変更(こちらの記事が参考になりました)
があるため、v5 を利用の方は下記実装と対応が少し異なります。
また、v5→v6 の変更点は下記記事が参考になりました。
下記以降は実装例となります。
Before
ここでは、about ページヘ遷移する際に、何らかの処理(セッションチェック、不正な遷移のチェック、等)を行いたいケースを想定しています。
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 を作成します。
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 で利用する。
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 は元から提供されている機能は少ないように思いますが、その分ソース上で柔軟に制御ができるのが良いところだなと思いました。
Discussion