この記事で使っている React Router のバージョンは 6.2.2 です。
React Routerは、React用のルーティングライブラリであり、SPA(Single Page Application)のナビゲーションを実装するのに役立ちます。具体的には、アプリケーションの異なるURLに対応する異なるコンポーネントやビューを表示するための仕組みを提供しています。
React RouterはURLとコンポーネントを紐づけているため同じURLに移動しようとした時、画面をそのままにします。しかしながら、しばしば同じURLに移動した時に画面をリセットした方が便利な画面になる時があります。これは例えば「メニューから同じ機能を呼び出す時にその機能の初期画面を呼び出す」という、いわゆるブラウザの更新処理と同じ変化をさせたい時です。これの実装例を紹介します。
使うのはReact Routerとグローバルな状態管理ライブラリの jotai です。jotai の部分は他のグローバルな状態管理を行う方法にも差し替えられます。実際のコードが次です。
pmndrs/jotai: 👻 Primitive and flexible state management for React
// Router.tsx import React from 'react'; import { atom, useAtom } from 'jotai'; import { Routes } from 'react-router'; import { Route } from 'react-router-dom'; // jotai でグローバルに使える状態を管理します。 // この key を書き変えたり、読んだり、参照したりしてコンポーネントを制御します。 export const globalRouteUniqueKeyAtom = atom(`${Math.random()}`); export const Router = () => { // jotai でキーを呼び出して const [globalRouteUniqueKey] = useAtom(globalRouteUniqueKeyAtom); // Routes の key にそれを置く。 // これで jotai を通じて key が書き換わるたびに Routes が再生成されます。 return ( <Routes key={globalRouteUniqueKey}> <Route path={appRouting.home.path} element={<HomePage />} /> </Routes> ) }
// MenuLink.tsx import React, { useCallback } from 'react'; import { NavLink } from 'react-router-dom'; import { globalRouteUniqueKeyAtom } from './Router'; import { useAtom } from 'jotai'; export const MenuLink: React.FC<{url: string; title: string;}> = (props) => { // jotai でキーへの書き込みを呼び出して const [, setRouteUniqueKey] = useAtom(globalRouteUniqueKeyAtom); // ランダムなキーを設定する関数を用意 const recreateRouteUniqueKey = useCallback(() => setRouteUniqueKey(`${Math.random()}`), [setRouteUniqueKey]); // リンクがクリックされたら↑の関数を呼び出します return ( <NavLink to={props.url} onClick={recreateRouteUniqueKey}> {props.title} </NavLink> ); };
Routes というルーティングの根本のコンポーネントに key をつけ、その key が適宜変わる様にするだけです。React の key はコンポーネントを識別する目印であり、keyが違うならば違うコンポーネントとして処理されます。つまり同じ場所にある同じコンポーネントであっても再生できます。
例では MenuLink で click した時にのみ再生成していますが、他のコンポーネントのどこかにも同じように key の変更処理を追加することで同様のコンポーネントの再生成ができます。key の変更処理を行う場所が多岐に渡るのであれば、keyの変更処理をフックにまとめておいた方が扱いやすいです。