react-routerのver6に伴う変更点
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
になったことで、 Route
や Link
は Routes
でレンダリングした親ルートに自動的に相対的となっています。
上記によって、現在の 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系もアップデートは続いているようなので、急ぐ必要はなさそうです。
参考記事
Discussion