はじめに
Reactで開発を進める上で必ずと言っていいほど使用されているReact Router
。
ドキュメントが充実しているので、目を通せば大体のことは、解決すると思いますが、使い方の整理の意味を込めて文章としてまとめます。
対象読者
React初学者
SPAにおけるルーティングのおさらい
さらっとですが、SPAにおけるルーティングについて整理します。
※ここら辺、理解してる人は読み飛ばして下さい。
SPAにおけるルーティングを一言で説明すると、『DOMの動的な書き換えによってページ遷移を擬似的に実現するとともに、ブラウザのセッション履歴をそれに同期させる事』 です。
SPAはサーバーへの初回リクエストに対して、アプリ全体が記述されたJSのコードと、そこで使用されるアセットファイルがごそっと返されます。
以降、ページ遷移はアプリが動的にDOMを書き換えることで、移動してるように見せてるに過ぎない点が大きな特徴です。即ち、ブラウザのアドレスバーのURLが書き換わっても、実際にサーバーへリクエストを投げることは原則的には無いという事です。
これは、リクエストされたURLに対して、そのURLに紐づく適切なページ内容をアプリケーションサーバーがクライアントに返すRailsやLaravelのようなフレームワークとは異なりますね。
では、SPAでルーティングを実現するために、どうしてるかというと、これには、History APIという技術が使われています。HTML5から導入されたpushStateとreplaceStateで、ブラウザのセッション履歴に任意のURLを追加したり、特定の履歴を書き換えたりしながら、JSによって履歴のURLを制御することを可能にしています。
そして、SPAでのルーティングの適用単位はコンポーネントです。
RailsやLaravel等は、Controllerがルーティングに対応する名前を持つViewを選び、それを使用してレスポンスを返しますが、Reactはルートのコンポーネントから階層を下り、「ここから先はこのコンポーネントがマウントされる、このパスの時は別のコンポーネントがマウントされるといったようにコンポーネントそのものがルーティングとなります。
上記を意識しながら、次セクションで実際に試してみましょう。
実際にルーティングを定義してみる
まずはreact-router-domをインストールします。
npm install react-router-dom
次にサンプルでいくつかコンポーネントを作っておきましょう。
export const Home = () => {
return (
<>
<h1>Homeページです</h1>
</>
);
};
export const Sample1 = () => {
return (
<>
<h1>Page01</h1>
</>
);
};
export const Sample02 = () => {
return (
<>
<h1>Page02</h1>
</>
);
};
次にsrc
直下にroute
ディレクトリを作成します。
その中に、ルーティングを定義していきます。
手順としては以下の通り
① ルーティング設定(URLとそれに対応するコンポーネントを決める)
② ①が決まったら、Linkタグを使用して、Linkを設置
コードを書く上で気をつけることは2点です。
・Router(BrowserRouter)の中にRouteを定義
・Routeタグにpathと、コンポーネントを定義
以下に例を示します。
import { React } from "react";
import { Route, Switch } from "react-router-dom";
import { Home } from "../component/reactRouter/Home";
import { Sample01 } from "../component/reactRouter/Sample01";
import { Sample02 } from "../component/reactRouter/Sample02";
export const RootRouter: React.VFC = () => (
<Switch>
<Route exact path="/">
<Home />
</Route>
<Route exact path="/sample01">
<Sample01 />
</Route>
<Route exact path="/sample02">
<Sample02 />
</Route>
</Switch>
);
続いて、App.tsx
に上記のルーティングを読み込んで、Linkタグでリンクを設置していきます。
import * as React from "react";
import { RootRouter } from "./route";
import { Link, BrowserRouter as Router } from "react-router-dom";
function App(): React.VFC {
return (
<div className="App">
<Router>
<RootRouter />
<Link to="/">Home</Link>
<br />
<Link to="/sample01">Page1</Link>
<br />
<Link to="/sample02">Page2</Link>
</Router>
</div>
);
}
export default App;
React Routerでパラメータを扱う
実案件では、URLパラメータを扱う場面は多々あります。以下にその方法を示します。
URLパラメータ
例えば、UserIdをAPIの引数にして、UserIdに応じたページを取得するというケース等、動的に変化する部分をReactRouterでどのように扱うのでしょうか。
サンプルとして以下のルーティングの追加と新しいコンポーネントを作成します。UserId:1のユーザーがログインしている状態というケースを想定して、サンプルを書きます。
(※ APIはJSONPlaceholderを使わせてもらいます)
URLパラメータを扱う場合、パスの書き方として/:id
といった書き方になります。:id
の部分は任意で書くことが可能で、例えば、/:userid
とかでも問題ありません。
import { Profile } from "../component/reactRouter/Profile";
export const RootRouter: React.VFC = () => (
<>
{/* 以下コンポーネントを追加 */}
<Route exact path="/user/:id">
<Profile />
</Route>
</>
);
以下が新しく作成したコンポーネントです。
**URLパラメーターを扱いたい場合は、useParams
を使用します。**これを使って、ルーティングで定義した:id
の部分を抽出し、取得したidを元にAPIを叩いています。
import React, { useState, useEffect } from "react";
import { useParams } from "react-router-dom";
export const Profile = () => {
const [user, setUser] = useState(null);
const { id } = useParams(); // useIdを取得
// useParamsを使って取得したIDを使ってAPIを叩く
useEffect(() => {
const fetchUser = async () => {
const res = await fetch(
`https://jsonplaceholder.typicode.com/users/${id}`
);
const userData = await res.json();
await setUser(userData);
};
fetchUser();
}, [id]);
return (
<>
<h1>Profile Detail</h1>
{user ? (
<ul>
<li>UserId: {user.id}</li>
<li>UserName: {user.name}</li>
<li>E-mail{user.email}</li>
<li>Address: {user.address.street}</li>
</ul>
) : (
<>Loading</>
)}
</>
);
};
最後に先ほど作成したHomeコンポーネントに遷移先を設置して、動作確認します。遷移先のパスは本来であれば、グローバルステートから、UserId情報を取得する形が一般的かと思いますが、サンプルとして/user/1
をベタ書きしてます。(本来であれば/user/:id
になる)
import { Link } from "react-router-dom";
export const Home = () => {
return (
<>
<h1>Homeページです</h1>
<div>
<Link exact to="/user/1">
Profile
</Link>
</div>
</>
);
};
最後に
他にも便利なhooksが用意されているので、公式ドキュメントに目を通しておくと良いかと思います。