react-routerのver6に伴う変更点

2022/06/15に公開

React でルーティングを実装するためのパッケージとして有名な「React Router」ですが、バージョン5と6で記述方法が異なります。

今回バージョン間の違いで苦戦をしてしまったので、違いを比較しながらその備忘録として記録しています。

一応アップグレードガイドを用意してあるのですが、割と今回のアップデートは破壊的変更が多く、導入には慎重になった方がいいかと。

まずはバージョン6をインストール

npm

npm install react-router-dom@6

yarn

yarn add react-router-dom@6

変更点の比較

React のプロジェクトを新規作成した段階のソースで説明していきます。

src/index.js に App コンポーネントをラップしてあげる形で BrowserRouter を指定します。

これはバージョン関係なく必須対応です。

import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';
import { BrowserRouter } from 'react-router-dom';

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
  <React.StrictMode>
    <BrowserRouter>
      <App />
    </BrowserRouter>
  </React.StrictMode>
);

// If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
reportWebVitals();

Switch 削除からの Routes に置き換え

src/App.jsx に対しての記述がバージョンアップで変更になっています。

バージョン5の時は、 path が URL に一致するコンポーネントのみ表示させるためのタグとして Routes ではなく、 Switch となっていました。

Routes になったことで、 RouteLinkRoutes でレンダリングした親ルートに自動的に相対的となっています。

上記によって、現在の URL に基づいて具体的なルートが最初で選択されるようになり、バージョン5のときのように記載順番で求めているルートに飛ばないという不具合が出なくなっています。

バージョン6では、下記のように変更になりました。

src/App.jsx

import * as React from "react";
import { Routes, Route, Link } from "react-router-dom";
import "./App.css";

function App() {
  return (
    <div className="App">
      <h1>Welcome to React Router!</h1>
      <Routes>
        <Route path="/" element={<Home />} />
        <Route path="about" element={<About />} />
      </Routes>
    </div>
  );
}

また、 Route の書き方も変更になっています。

// Route内でコンポーネントを指定する方法(バージョン5)
<Route exact path="/">
  <Home />
</Route>
<Route path = "/users" component = {Users} />


// Routeの属性でコンポーネントを指定(バージョン6)
<Route exact path="/" component={Home} />
// 相対パスになったため、「/」を省略可能
<Route path = "users" element = {<Users />} />

大きく変更点は4つです。

  • バージョンアップに伴い、element 属性でコンポーネントを指定する形となっています
  • Route タグのデフォルトが完全一致となったため、exact 属性の指定が不要となりました
  • パスとリンクの両方が親ルートに相対的になりました
  • ネストも記述しやすくなりました

上記にも記載しましたが、 Route によるネストもやりやすくなっています。

const App = () =>  {
  return (
    <BrowserRouter>
      <Routes>
        <Route path="/" element={<Home />} />
        <Route path="users/*" element={<Users />} />
      </Routes>
    </BrowserRouter>
  );
}

const Users = () => {
  return (
    <div>
      <nav>
        <Link to="me">My Profile</Link>
      </nav>

      <Routes>
        <Route path="/" element={<UsersIndex />} />
        <Route path=":id" element={<UserProfile />} />
        <Route path="me" element={<OwnUserProfile />} />
      </Routes>
    </div>
  );
}

やはり、相対パスへ変更になったのはとても大きいですね。

useHistory から useNavigate への変更

これまで利用していた useHistory から useNavigate へ変更する必要があります。

バージョン5の記述方法。

import { useHistory } from "react-router-dom";

function App() {
  let history = useHistory();
  function handleClick() {
    history.push("/home");
  }
  return (
    <div>
      <button onClick={handleClick}>go home</button>
    </div>
  );
}

バージョン6の記述方法。

import { useNavigate } from "react-router-dom";

function App() {
  let navigate = useNavigate();
  function handleClick() {
    navigate("/home");
  }
  return (
    <div>
      <button onClick={handleClick}>go home</button>
    </div>
  );
}

useNavigate を利用する際、履歴を初期化する際は navigate(to, { replace: true }) を使用するようになります。

また state が必要な時は、 navigate(to, { state }) と記載します。

履歴の移動で利用する go 関係は useNavigate の利用に置き換わります。

import { useHistory } from "react-router-dom";

//ver5
function App() {
  const { go, goBack, goForward } = useHistory();

  return (
    <>
      <button onClick={() => go(-2)}>
        Go 2 pages back
      </button>
      <button onClick={goBack}>Go back</button>
      <button onClick={goForward}>Go forward</button>
      <button onClick={() => go(2)}>
        Go 2 pages forward
      </button>
    </>
  );
}


//ver6
function App() {
  const navigate = useNavigate();

  return (
    <>
      <button onClick={() => navigate(-2)}>
        Go 2 pages back
      </button>
      <button onClick={() => navigate(-1)}>Go back</button>
      <button onClick={() => navigate(1)}>
        Go forward
      </button>
      <button onClick={() => navigate(2)}>
        Go 2 pages forward
      </button>
    </>
  );
}

互換機能を開発中らしい...

上記の通り、バージョン6へのアップデートの一部のみ紹介でしたが、その他大きく破壊的変更が入っています。

これまでバージョン5を利用していた方がすぐにバージョンアップできるかというとそうでもないです。

どうやら破壊的変更は理解しているようで、互換性を持つ機能を開発中であるようですし、バージョン5系もアップデートは続いているようなので、急ぐ必要はなさそうです。

参考記事

https://github.com/remix-run/react-router

https://reactrouter.com/en/6.5.0/upgrading/v5

GitHubで編集を提案

Discussion