Open9

React Router

どるあがどるあが

なんか難しそうだし、Spring使えばこのあたりは簡単なのではないかと思う。SpringとReact、どちらも使うための環境構築が必要か。

どるあがどるあが

恐ろしいほど簡単にページ遷移できるな

App.js
import { BrowserRouter, Link, Switch, Route } from "react-router-dom";

import React from "react";
import { Home } from "./Home";
import { Page1 } from "./Page1";
import { Page2 } from "./Page2";

export const App = () => {
  return (
    // ルーティングするページは全てBrowserRouterタグで囲む
    <BrowserRouter>
    {/* リンクを表すにはLinkタグ、URLはtoで指定 */}
      <div>
        <Link to="/">Home</Link>
        <br />
        <Link to="/page1">Page1</Link>
        <br />
        <Link to="/page2">Page2</Link>
      </div>
      <Switch>
        {/* 指定されたページ遷移はRouteタグで行う */}
        {/* 完全一致のためにexactを付与する */}
        <Route exact path="/">
          <Home />
        </Route>
        <Route path="/page1">
          <Page1 />
        </Route>
        <Route path="/page2">
          <Page2 />
        </Route>
      </Switch>
    </BrowserRouter>
  );
};

どるあがどるあが

Routeタグでrender関数がpropsで受け取るものの中身



{history: Object, location: Object, match: Object, staticContext: undefined}
history: Object
  length: 1
  action: "POP"
  location: Object
  createHref: ƒ createHref() {}
  push: ƒ push() {}
  replace: ƒ replace() {}
  go: ƒ go() {}
  goBack: ƒ goBack() {}
  goForward: ƒ goForward() {}
  block: ƒ block() {}
  listen: ƒ listen() {}
location: Object
  pathname: "/page1/detailA"
  search: ""
  hash: ""
  state: undefined
match: Object
  path: "/page1"
  url: "/page1"
  isExact: false
  params: Object
  staticContext: undefined
​
App.js
import { BrowserRouter, Link, Switch, Route } from "react-router-dom";

import React from "react";
import { Home } from "./Home";
import { Page1 } from "./Page1";
import { Page2 } from "./Page2";
import { Page1DetailA } from "./Page1DetailA";
import { Page1DetailB } from "./Page1DetailB";

export const App = () => {
  return (
    // ルーティングするページは全てBrowserRouterタグで囲む
    <BrowserRouter>
      {/* リンクを表すにはLinkタグ、URLはtoで指定 */}
      <div>
        <Link to="/">Home</Link>
        <br />
        <Link to="/page1">Page1</Link>
        <br />
        <Link to="/page2">Page2</Link>
      </div>
      <Switch>
        {/* 指定されたページ遷移はRouteタグで行う */}
        {/* 完全一致のためにexactを付与する */}
        <Route exact path="/">
          <Home />
        </Route>
        <Route
          path="/page1"
          {/* propsからmatchのurlを取り出す */}
          render={({ match: { url } }) => (
            <Switch>
              <Route exact path={url}>
                <Page1 />
              </Route>
              {/* urlを"/page1"に確定する */}
              <Route path={`${url}/detailA`}>
                <Page1DetailA />
              </Route>
              <Route path={`${url}/detailB`}>
                <Page1DetailB />
              </Route>
            </Switch>
          )}
        />

        <Route path="/page2">
          <Page2 />
        </Route>
      </Switch>
    </BrowserRouter>
  );
};


どるあがどるあが

Routerの切り出し

Router.jsx
import { BrowserRouter, Link, Switch, Route } from "react-router-dom";

import { Home } from "../Home";
import { Page1 } from "../Page1";
import { Page2 } from "../Page2";
import { Page1DetailA } from "../Page1DetailA";
import { Page1DetailB } from "../Page1DetailB";
import { page1Routes } from "./Page1Routes";

export const Router = () => {
  return (
    <Switch>
      {/* 指定されたページ遷移はRouteタグで行う */}
      {/* 完全一致のためにexactを付与する */}
      <Route exact path="/">
        <Home />
      </Route>
      <Route
        path="/page1"
        render={({ match: { url } }) => (
          // switch文の中で、配列を呼び出しループする
          <Switch>
            {/* 
            before:
            <Route exact path={url}>
              <Page1 />
            </Route>
            <Route path={`${url}/detailA`}>
              <Page1DetailA />
            </Route>
            <Route path={`${url}/detailB`}>
              <Page1DetailB />
            </Route>
            */}
            {/* map関数でpage1Routes配列を一つ取り出し、
            route変数に渡す */}
            {/* keyはどの要素が変更、追加もしくは削除されたのかを 
            React が識別するのに役立つ */}
            {page1Routes.map((route) => (
              <Route
                key={route.path}
                exact={route.exact}
                path={`${url}${route.path}`}
              >
                {route.children}
              </Route>
            ))}
          </Switch>
        )}
      />

      <Route path="/page2">
        <Page2 />
      </Route>
    </Switch>
  );
};

Page1Routes.jsx
import { Page1 } from "../Page1";
import { Page1DetailA } from "../Page1DetailA";
import { Page1DetailB } from "../Page1DetailB";

export const page1Routes = [
  {
    path: "/",
    exact: true,
    children: <Page1 />
  },
  {
    path: "/detailA",
    exact: false,
    children: <Page1DetailA />
  },
  {
    path: "/detailB",
    exact: false,
    children: <Page1DetailB />
  }
];

どるあがどるあが

URLパラメータとクエリパラメータの取得

Page2.jsx
import { Link } from "react-router-dom";

export const Page2 = () => {
  return (
    <div>
      <h1>Page2です</h1>
      {/* URLパラメータ100を取得して表示 */}
      <Link to="/page2/100">URL Parameter</Link>
      <br />
      {/* クエリパラメータhogehogeを取得して表示 */}
      <Link to="/page2/100?name=hogehoge">Query Parameter</Link>
    </div>
  );
};

Page2Routes.jsx
import { Page2 } from "../Page2";
import { UrlParameter } from "../UrlParameter";

export const page2Routes = [
  {
    path: "/",
    exact: true,
    children: <Page2 />
  },
  {
    // urlの後ろ(/page2/~)の数値をidに格納
    path: "/:id",
    exact: false,
    children: <UrlParameter />
  }
];


UrlParameter.jsx
import { useParams, useLocation } from "react-router-dom";

export const UrlParameter = () => {
  // /:idで指定されている値を取得する
  const { id } = useParams();
  // 様々なパラメータ情報を取得する
  const { search } = useLocation();
  // クエリパラメータを簡単に扱える
  const query = new URLSearchParams(search);
  return (
    <div>
      <h1>UrlParameterです</h1>
      <p>パラメータは {id} です</p>
      {/* クエリパラメータの取得 
      ~?name=hogehogeからhogehogeを取得する */}
      <p>パラメータは {query.get("name")} です</p>
    </div>
  );
};

URLSearchParamsクラスについて

https://qiita.com/ovrmrw/items/1c1564481c4ca9cc4351

useLocation()の中身
{pathname: "/page2/100", search: "?name=hogehoge", hash: "", state: undefined}
  pathname: "/page2/100"
  search: "?name=hogehoge"
  hash: ""
  state: undefined
どるあがどるあが

ページ間で値を渡す際には<Link>を使用する
ページ遷移をする場合は、useHistoryを使用することが多い

Page1.jsx
import { Link, useHistory } from "react-router-dom";

export const Page1 = () => {
  // 1から100までの無意味な配列
  const arr = [...Array(100).keys()];

  // ページ遷移はuseHistoryを使う
  const history = useHistory();
  const onClickDetailA = () => history.push("/page1/detailA");

  return (
    <div>
      <h1>Page1です</h1>
      {/* pathの正確な書き方 */}
      {/* stateに値arrを設定してpathnameに渡す */}
      <Link to={{ pathname: "/page1/detailA", state: arr }}>DetailA</Link>
      <br />
      <Link to="/page1/detailA">DetailB</Link>
      <br />
      <button onClick={onClickDetailA}>DetailA</button>
    </div>
  );
};

Page1DetailA.jsx
import { useHistory, useLocation } from "react-router-dom";

export const Page1DetailA = () => {
  // useLocationのstateにより受け取る
  const { state } = useLocation();
  //ブラウザの遷移はuseHistoryを使う
  const history = useHistory();

  // ブラウザの戻る機能のようなもの
  const onClickBack = () => history.goBack();

  return (
    <div>
      <h1>Page1DetailAです</h1>
      <button onClick={onClickBack}>戻る</button>
    </div>
  );
};

useLocationの中身
{pathname: "/page1/detailA", state: Array(100), search: "", hash: "", key: "w3y4sc"}
pathname: "/page1/detailA"
state: Array(100)
search: ""
hash: ""
key: "w3y4sc"
どるあがどるあが

** 404ページについて
以下のようにRouteの最後につける。アスタリスクでその他を表す

Router.tsx
<Route
        path="/home"
        render={({ match: { url } }) => (
          <Switch>
            {homeRoutes.map((route) => (
              <Route
                key={route.path}
                exact={route.exact}
                path={`${url}${route.path}`}
              >
                {route.children}
              </Route>
            ))}
          </Switch>
        )}
      />
      <Route path="*">
        <Page404 />
      </Route>

また、/home/xxxxのように階層が異なる場合にも適用できるようにするには、Routesに追加していく

HomeRoutes.tsx
export const homeRoutes = [
  {
    path: "/",
    exact: true,
    children: <Home />
  },
  {
    path: "/user_management",
    exact: false,
    children: <UserManagement />
  },
  {
    path: "/setting",
    exact: false,
    children: <Setting />
  },
  {
    path: "*",
    exact: false,
    children: <Page404 />
  }
];

どるあがどるあが

ver18での変更

switchタグが無くなって、Routesタグになった
確かにSwitchってよくわからんかった

App18.jsx
const App = () => {
  return (
    <BrowserRouter>
      <Routes> //ここが変わったかな
        <Route path={`/`} element={<Home />} />
        <Route path={`/page1/`} element={<Page1 />} />
        <Route path={`/page2/`} element={<Page2 />} />
      </Routes>
    </BrowserRouter>
  );
};

https://ralacode.com/blog/post/how-to-use-react-router/