はじめに
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のようにコンポーネントに渡してあげる必要がありました。
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の効力が発揮されそうです。
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>
には、任意のコンポーネントを渡すことができます。
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を書くことができます。
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を変更したり、コンポーネントを配置しなおす際になどに、修正しなくてよいという面で便利なのかなと思っています。
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の新機能