21
14

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

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

Posted at

はじめに

2021年11月にReact Routerのv6がリリースされました。一年ほど前からベータ版はあったそうです。
Reactでナビゲーションを利用したいと思ったことがある人なら、一度はReact Routerを触ったことがあると思います。そんなReact Routerv6の変更点についてまとめていきます。基本的にはReact Router v6 - Remix Runに沿って、書いていきます。
(※私は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です。これは、

<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
React Router Overview
React Router v6の新機能

21
14
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
21
14

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?