React Router v6 での変更点についてまとめてみた

## はじめに
2021年11月にReact  Routerのv6がリリースされました。一年ほど前からベータ版はあったそうです。
Reactでナビゲーションを利用したいと思ったことがある人なら、一度はReact  Routerを触ったことがあると思います。そんなReact  Routerv6の変更点についてまとめていきます。基本的には[React Router v6 - Remix Run](https://remix.run/blog/react-router-v6)に沿って、書いていきます。
（※私はReactの知識や経験が浅いので、間違った表現などがあると思いますが、ご容赦ください...。コメントで指摘していただけると、非常に勉強になります！）

## 対象者
この記事は下記のような人を対象にしています。

- Reactを使用している人

## インストール方法
```
npm add react-router-dom@6
```
or

```
npm add react-router-dom@latest
```

## 変更点

### URLのパラメータの取得が容易に
現在のURLパラメーターにアクセスできる`useParams()`フックが用意されました。

#### v5以前
Routeからコンポーネントへ情報を受け渡すには、通常のpropsのようにコンポーネントに渡してあげる必要がありました。

```App.js
import * as React from "react";
import { Switch, Route } from "react-router-dom";

class App extends React.Component {
  render() {
    return (
      <Switch>
        <Route
          path="blog/:id"
          render={({ match }) => (
            //ここでidを<BlogPost>に渡す必要がある
            <BlogPost id={match.params.id} />
          )}
        />
      </Switch>
    );
  }
}

class BlogPost extends React.Component {
  render() {
    return (
      <>
        {/* 孫要素にもidを渡していく必要がある */}
        <PostHeader id={this.props.id} />
      </>
    );
  }
}
```

#### v6
v6では、コンポーネントにparamを渡すのではなく、useParamsを用いて各コンポーネントでparamを得られるようになります。ルーターはいくつかの状態（現在のURLパラメーター）を認識しており、任意の場所でフックを使用できます。階層が深くなるほど、useParamsの効力が発揮されそうです。

```App.js
import { Routes, Route, useParams } from "react-router-dom";

function App() {
  return (
    <Routes>
      <Route path="blog/:id" element={<BlogPost />} />
    </Routes>
  );
}

function BlogPost() {
  // このようにuseParamsを用いて、paramにアクセスができる
  let { id } = useParams();
  return (
    <>
      <PostHeader />
      {/* ... */}
    </>
  );
}

function PostHeader() {
  // useParamsは任意の場所で実行することが可能
  let { id } = useParams();
}
```

### ネストされたルーターをよりシンプルに

#### v6
- `<Switch>`の代わりに`<Routes>`を使用するようになります。`<Switch>`では、上から順番にルートを探すような挙動でしたが、`<Routes>`では現在のURLに最適なルートを選ぶようになりました。
- `<Route element>`には、任意のコンポーネントを渡すことができます。

```Router.js
import { render } from "react-dom";
import { BrowserRouter } from "react-router-dom";
// import your route components too

render(
  <BrowserRouter>
    <Routes>
      <Route path="/" element={<App />}>
        <Route index element={<Home />} />
        <Route path="teams" element={<Teams />}>
          <Route path=":teamId" element={<Team />} />
          <Route path="new" element={<NewTeamForm />} />
          <Route index element={<LeagueStandings />} />
        </Route>
      </Route>
    </Routes>
  </BrowserRouter>,
  document.getElementById("root")
);
```

ここで、`<Route index element={<Home />} />`や`<Route index element={<LeagueStandings />} />`は、デフォルトで表示されるルートのようなものです。「/」では、`<Home>`がレンダリングされます。

- ルートの先端（葉の部分）には、`<Route exact>`を追加していましたが、その代わりにパスの最後に*を追加して使用することができます。
つまり、次のようにRouter.jsxを書くことができます。
 
```App.js
import { Routes, Route } from "react-router-dom";

function App() {
  return (
    <Routes>
      <Route path="/" element={<Layout />}>
        <Route path="users" element={<Users />}>
          <Route index element={<UsersIndex />} />

          {/* このルートでは、/users/と一致し、<UsersSplat>で定義されるルーティングが実行できます */}
          <Route path="*" element={<UsersSplat />} />
        </Route>
      </Route>
    </Routes>
  );
}

function UsersSplat() {
  // このコンポーネントが呼び出されたときに、初めてルーティングが定義されます。動的ルーティングが可能であり、/users/内でレンダリングされるため、/usersが基準となります。
  return (
    <Routes>
      <Route path=":id" element={<UserProfile />}>
        <Route path="friends" element={<UserFriends />} />
        <Route path="messages" element={<UserMessages />} />
      </Route>
    </Routes>
  );
}
```

v5以前のReact  Routerでは、複数のルートがあいまいなURLに一致した場合に備える必要がありました。v6では、より賢くなった（らしい）ので、その必要がありません。
ここで、あいまいなURLとは、上記の例では`teams/new`です。これは、

```js
<Route path="teams/:teamId" element={<Team />} />
<Route path="teams/new" element={<NewTeamForm />} />
```
の両方に一致してしまいます。v5では常に上の`<Route path="teams/:teamId" element={<Team />} />`のパスとみなされてしまいます。しかし、v6では`teams/new`のパスのほうが、`teams/teamId`のパスより最適と判断されるようになり、`<NewTeamForm />`がレンダリングされるということです。

### 相対的なルートとリンク
相対的な`<Route path>`と`<Link to>`が改善されました。

- 相対`<Route path>`は、常に親ルートが基準になります。必ずしも/からルーティングを行う必要がなくなりました。
- 相対`<Link to>`は、常にルートパスが基準になります。検索文字列が含まれている場合にのみ（`<Link to="?framework=react">`）、現在の場所のパス名が基準になります。
- 相対`<link to>`の値は、`<a href>`よりあいまいさが少なく、現在のURLの末尾にスラッシュがあるかどうかは関係なく、常に同じ場所を指します。

親のURLを変更したり、コンポーネントを配置しなおす際になどに、修正しなくてよいという面で便利なのかなと思っています。

```Home.js
import {
  Routes,
  Route,
  Link,
  Outlet
} from "react-router-dom";

function Home() {
  return <h1>Home</h1>;
}

function Dashboard() {
  return (
    <div>
      <h1>Dashboard</h1>
      <nav>
        <Link to="invoices">Invoices</Link>{" "}
        <Link to="team">Team</Link>
      </nav>
      <hr />
      <Outlet />
    </div>
  );
}

function Invoices() {
  return <h1>Invoices</h1>;
}

function Team() {
  return <h1>Team</h1>;
}

function App() {
  return (
    <Routes>
      <Route path="/" element={<Home />} />
      <Route path="dashboard" element={<Dashboard />}>
        <Route path="invoices" element={<Invoices />} />
        <Route path="team" element={<Team />} />
      </Route>
    </Routes>
  );
}
```



## おわりに
React  Router v6についてまとめました。初めてのQiita投稿なので、指摘点があれば何でもお待ちしています。ご覧いただきありがとうございました！

## 参考記事
[React Router v6 - Remix Run](https://remix.run/blog/react-router-v6)
[React Router Overview](https://reactrouter.com/docs/en/v6/getting-started/overview#configuring-routes)
[React Router v6の新機能](https://ichi.pro/react-router-v-6-no-shin-kino-54507686506060)