react-route-domのルーティングをv6で書き直す

## はじめに

Udemyの講座『Reactに入門した人のためのもっとReactが楽しくなるステップアップコース完全版』の「セクション12：実践アプリ作成」に取り組んでいます。

https://www.udemy.com/course/react_stepup/

講座ではCodeSandbox上でreact-router-domのv5を使用されていますが、私はローカル環境でv6を使用しています。

v5とv6では結構変化があり、苦労して対応したので記録しておきます。

## 環境

- React：18.2.0
- TypeScript：5.2.2
- react-router-dom：6.21.1

## v5のコード

修正前のコードです。

```react: Router.tsx
<Switch>
    <Route exact path="/">
      <Login />
    </Route>
    <Route
      path="/home"
      render={({ match: { url } }) => (
        <Switch>
          {homeRoutes.map((route) => (
            <Route
              key={route.path}
              exact={route.exact}
              path={`${url}${route.path}`}
            >
              {route.children}
            </Route>
          ))}
        </Switch>
      )}
    />
    <Route path="*">
      <Page404 />
    </Route>
</Switch>
```

```react:HomeRouters.tsx
import { Home } from "../components/pages/Home";
import { UserManagement } from "../components/pages/UserManagement";
import { Setting } from "../components/pages/Setting";
import { Page404 } from "../components/pages/Page404";

export const homeRoutes = [
  {
    path: "/",
    exact: true,
    children: <Home />,
  },
  {
    path: "/user_management",
    exact: false,
    children: <UserManagement />,
  },
  {
    path: "/setting",
    exact: false,
    children: <Setting />,
  },
  {
    path: "*",
    exact: false,
    children: <Page404 />,
  },
];
```

## v6のコード

修正後のコードです。

まず、ループを使わないで書くと以下のようになります。

```react:Router.tsx
import { FC, memo } from "react";
import { Route, Routes } from "react-router-dom";
import { Login } from "../components/pages/Login";
import { Home } from "../components/pages/Home";
import { UserManagement } from "../components/pages/UserManagement";
import { Setting } from "../components/pages/Setting";
import { Page404 } from "../components/pages/Page404";

export const Router: FC = memo(() => {
  return (
    <Routes>
      <Route path="/" element={<Login />} />
      <Route path="home">
        <Route index={true} element={<Home />} />
        <Route path="user_management" element={<UserManagement />} />
        <Route path="setting" element={<Setting />} />
      </Route>
      <Route path="*" element={<Page404 />}/>
    </Routes>
  )
});
```

### 解説

v6では`<Switch>`は非推奨になり、代わりに`<Routes>`を使います。

遷移先のコンポーネントの指定の仕方も結構変わりましたね。

```react
// v5
<Route exact path="/">
  <Login />
</Route>

// v6
<Route path="/" element={<Login />} />
```

ネストする場合は、親の`<Route></Route>`の中に子を入れていきます。

今回の例でいうと、`/home`の下に`/home/user_management`と`/home/setting`があるので、以下のように書きます。

```react
<Route path="home">
    <Route index={true} element={<Home />} />
    <Route path="user_management" element={<UserManagement />} />
    <Route path="setting" element={<Setting />} />
</Route>
```

### 設定を別ファイルに切り出す

ルーティングの設定情報をHomeRoutes.tsxに切り出し、ループを使って書くと以下のようになります。

```react:Router.tsx
import { FC, memo, ReactNode } from "react";
import { Route, Routes } from "react-router-dom";
import { Login } from "../components/pages/Login";
import { homeRoutes } from "./HomeRoutes";
import { Page404 } from "../components/pages/Page404";

export const Router: FC = memo(() => {
  return (
    <Routes>
     <Route path="/" element={<Login />} />
     <Route path="home">
      {homeRoutes.map((route: {
          name: string, 
          path?: string, 
          index: boolean, 
          children: ReactNode 
      }) => (
        <Route
          key={route.name}
          index={route.index}
          path={route.path}
          element={route.children} />
      ))}
     </Route>
     <Route path="*" element={<Page404 />}/>
    </Routes>
  )
});
```

```react:HomeRoutes.tsx
import { Home } from "../components/pages/Home";
import { Setting } from "../components/pages/Setting";
import { UserManagement } from "../components/pages/UserManagement";

export const homeRoutes = [
  {
    name: "home",
    index: true,
    children: <Home />
  },
  {
    name: "user_management",
    path: "user_management",
    index: false,
    children: <UserManagement />
  },
  {
    name: "setting",
    path: "setting",
    index: false,
    children: <Setting />
  },
]
```

## 終わりに

homeRoutesのnameプロパティは完全にmapのkeyのためだけに付与しています。。

最初はhomeのpathを"home"にしてpathをkeyにしようとしたのですが、1つ上の`<Route>`とpathが被ってエラーになってしまうんですよね。

他に良い書き方があれば、ぜひコメントで教えてください！

## 参考

https://reactrouter.com/en/main/upgrading/v5#upgrade-to-react-router-v6

https://kinsta.com/jp/knowledgebase/attempted-import-error-switch-is-not-exported-from-react-router-dom/

https://stackoverflow.com/questions/72113415/react-route-v6-useroutes-index-true-property

https://qiita.com/kurab/items/8aa30074b703ca15157b#switch-%E3%82%92-routes-%E3%81%AB%E5%A4%89%E6%9B%B4