19
15

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.

SPAにおけるルーティング〜React Router初歩

Last updated at Posted at 2021-05-05

はじめに

Reactで開発を進める上で必ずと言っていいほど使用されているReact Router

ドキュメントが充実しているので、目を通せば大体のことは、解決すると思いますが、使い方の整理の意味を込めて文章としてまとめます。

公式ドキュメント | React Router

対象読者

React初学者

SPAにおけるルーティングのおさらい

さらっとですが、SPAにおけるルーティングについて整理します。
※ここら辺、理解してる人は読み飛ばして下さい。

SPAにおけるルーティングを一言で説明すると、『DOMの動的な書き換えによってページ遷移を擬似的に実現するとともに、ブラウザのセッション履歴をそれに同期させる事』 です。

SPAはサーバーへの初回リクエストに対して、アプリ全体が記述されたJSのコードと、そこで使用されるアセットファイルがごそっと返されます。

以降、ページ遷移はアプリが動的にDOMを書き換えることで、移動してるように見せてるに過ぎない点が大きな特徴です。即ち、ブラウザのアドレスバーのURLが書き換わっても、実際にサーバーへリクエストを投げることは原則的には無いという事です。

これは、リクエストされたURLに対して、そのURLに紐づく適切なページ内容をアプリケーションサーバーがクライアントに返すRailsやLaravelのようなフレームワークとは異なりますね。

では、SPAでルーティングを実現するために、どうしてるかというと、これには、History APIという技術が使われています。HTML5から導入されたpushStatereplaceStateで、ブラウザのセッション履歴に任意のURLを追加したり、特定の履歴を書き換えたりしながら、JSによって履歴のURLを制御することを可能にしています。

そして、SPAでのルーティングの適用単位はコンポーネントです。
RailsやLaravel等は、Controllerがルーティングに対応する名前を持つViewを選び、それを使用してレスポンスを返しますが、Reactはルートのコンポーネントから階層を下り、「ここから先はこのコンポーネントがマウントされる、このパスの時は別のコンポーネントがマウントされるといったようにコンポーネントそのものがルーティングとなります。

上記を意識しながら、次セクションで実際に試してみましょう。

実際にルーティングを定義してみる

まずはreact-router-domをインストールします。

npm install react-router-dom

次にサンプルでいくつかコンポーネントを作っておきましょう。

Home.tsx
export const Home = () => {
  return (
    <>
      <h1>Homeページです</h1>
    </>
  );
};
Sample01.tsx
export const Sample1 = () => {
  return (
    <>
      <h1>Page01</h1>
    </>
  );
};
Sample02.tsx
export const Sample02 = () => {
  return (
    <>
      <h1>Page02</h1>
    </>
  );
};

次にsrc直下にrouteディレクトリを作成します。
その中に、ルーティングを定義していきます。

手順としては以下の通り
① ルーティング設定(URLとそれに対応するコンポーネントを決める)
② ①が決まったら、Linkタグを使用して、Linkを設置

コードを書く上で気をつけることは2点です。
・Router(BrowserRouter)の中にRouteを定義
・Routeタグにpathと、コンポーネントを定義

以下に例を示します。

route/index.tsx(コンポーネントの読み込みは任意で)
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タグでリンクを設置していきます。

App.tsx
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.gif

React Routerでパラメータを扱う

実案件では、URLパラメータを扱う場面は多々あります。以下にその方法を示します。

URLパラメータ

例えば、UserIdをAPIの引数にして、UserIdに応じたページを取得するというケース等、動的に変化する部分をReactRouterでどのように扱うのでしょうか。

サンプルとして以下のルーティングの追加と新しいコンポーネントを作成します。UserId:1のユーザーがログインしている状態というケースを想定して、サンプルを書きます。
(※ APIはJSONPlaceholderを使わせてもらいます)

URLパラメータを扱う場合、パスの書き方として/:idといった書き方になります。:idの部分は任意で書くことが可能で、例えば、/:useridとかでも問題ありません。

route/index.tsx(抜粋)
import { Profile } from "../component/reactRouter/Profile";

export const RootRouter: React.VFC = () => (
  <>
    {/* 以下コンポーネントを追加 */}
    <Route exact path="/user/:id">
      <Profile />
    </Route>
  </>
);

以下が新しく作成したコンポーネントです。
**URLパラメーターを扱いたい場合は、useParamsを使用します。**これを使って、ルーティングで定義した:idの部分を抽出し、取得したidを元にAPIを叩いています。

Profile.tsx
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になる)

Home.tsx
import { Link } from "react-router-dom";

export const Home = () => {
  return (
    <>
      <h1>Homeページです</h1>
      <div>
        <Link exact to="/user/1">
          Profile
        </Link>
      </div>
    </>
  );
};

react-router2.gif

最後に

他にも便利なhooksが用意されているので、公式ドキュメントに目を通しておくと良いかと思います。

19
15
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
19
15

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?