Reactでurlごとにコンポーネントを出しわけるルーティングを設定する

Reactでルーティングの設定をするためにreact-router-domを使用します。

パッケージを使わずに自分でURLごとに切り出すコードを書いてもいい気もしますが、かなり有名なパッケージですしせっかくなので使ってみます。

ディレクトリ構成とかは違うと思いますが、基本的な使い方自体は簡単なのでうまく読み替えてください。

react-router-domをインストールする

以下のコマンドを実行してreact-router-domをインストールします。

npm i -S react-router-dom

package.jsonを確認すると現時点の最新は6.0.1になっています。

// package.jsonの一部

   "react-dom": "17.0.2",
   "react-router-dom": "^6.0.1",

ちなみに6系にアップデートされた際にいろいろと変更が入っているようです。

urlごとにコンポーネントを出しわけるルーティングを設定する

以下のように書くことによってルートにアクセスされたときはTopコンポーネントを表示して、/page1にアクセスされたときはPage1コンポーネントを表示することができます。

また、404 not foundの場合はpathパラメータをつけずに最後においておけば、見つからなかった時に表示されます。

// frontend/app_router/index.tsx

import { BrowserRouter, Route, Routes} from "react-router-dom";

import Top from "../pages/Top"
import Page1from "../pages/Page1"
import Page404 from "../page/Page404";

const AppRouter = () => {
 return (
   <BrowserRouter>
     <Routes>
       <Route exact path="/" element={<Top />} />
       <Route exact path="/page1" element={<Page1 />} />
       <Route component={<Page404 />} />
     </Routes>
   </BrowserRouter>
 );
};

export default AppRouter;

Routesの中にを並べていくことでルーティング事のコンポーネントを設定できます。

Routeのexactはpathに指定した文字列とアクセスしたpathが完全一致した場合のみコンポーネントを返す設定です。

exactを書いておくとtrueになり、省略するとfalseになります。

はまったポイント

以下のように書いて何も表示されませんでした。

// 古い例!

import { BrowserRouter, Route, Switch} from "react-router-dom";

import Top from "../pages/Top"
import Page1from "../pages/Page1"

const AppRouter = () => {
 return (
   <BrowserRouter>
     <Switch>
       <Route exact path="/" component={Top} />
       <Route exact path="/page1" component={Page1} />
     </Switch>
   </BrowserRouter>
 );
};

export default AppRouter;

コンパイル時やブラウザにこんなエラーが出てました。

WARNING in ./frontend/app_router/index.tsx 9:33-39
export 'Switch' (imported as 'Switch') was not found in 'react-router-dom' (possible exports: BrowserRouter, HashRouter, Link, MemoryRouter, NavLink, Navigate, Outlet, Route, Router, Routes, UNSAFE_LocationContext, UNSAFE_NavigationContext, UNSAFE_RouteContext, createRoutesFromChildren, createSearchParams, generatePath, matchPath, matchRoutes, renderMatches, resolvePath, useHref, useInRouterContext, useLinkClickHandler, useLocation, useMatch, useNavigate, useNavigationType, useOutlet, useParams, useResolvedPath, useRoutes, useSearchParams)
Warning: React.jsx: type is invalid -- expected a string (for built-in components) or a class/function (for composite components) but got: undefined. You likely forgot to export your component from the file it's defined in, or you might have mixed up default and named imports.

Check the render method of `AppRouter`.
   at AppRouter
Uncaught Error: Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: undefined. You likely forgot to export your component from the file it's defined in, or you might have mixed up default and named imports.
react-dom.development.js?61bb:20085 The above error occurred in the <Location.Provider> component:

...

Consider adding an error boundary to your tree to customize error handling behavior.
Visit https://reactjs.org/link/error-boundaries to learn more about error boundaries.
Error: Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: undefined. You likely forgot to export your component from the file it's defined in, or you might have mixed up default and named imports.

まず、SwitchはRoutesに名前が変わっているので、Routesを使いましょう。

次に引数のcomponentもelementに変わって、以前はcomponent={Top}というように書いていましたが、6系からelement={}という風に書きます。