[React] React Router 前編

React初心者がReact Routerについて勉強した時のメモです。
コード部分が長くなってしまったので前編後編の2回に分けます。
今回は、

- 基本的なページ遷移
- ネストされたページ遷移
- ルーティング分割
- URLパラメーターの値の受け渡し

です。

事前に`react-router-dom`をインストール。
## 基本的なページ遷移
```react
import { BrowserRouter, Link, Switch, Route } from "react-router-dom";

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

export default function App() {
  return (
    <BrowserRouter>
      <div className="App">
        <Link to="/">Home</Link>
        <br />
        <Link to="/page1">Page1</Link>
        <br />
        <Link to="/page2">Page2</Link>

        <Switch>
          <Route exact path="/">
            <Home />
          </Route>
          <Route path="/page1">
            <Page1 />
          </Route>
          <Route path="/page2">
            <Page2 />
          </Route>
        </Switch>
      </div>
    </BrowserRouter>
  );
}
```
`BrowserRouter`で全体を囲み`Link`にパスを書きリンクを生成。
どのパスの時にどのコンポーネントをレンダリングするかは、`Switch`で全体を囲み、コンポーネントを`Route`で囲みパスを指定。
`exact`をつけることで完全一致のみになる。
`exact`がないと`/`でレンダリングされるので、`Page1` と `Page2`はレンダリングされず`Home`のみのレンダリングになるので注意。


## ネストされたページ遷移
```react:App.js
import { Home } from "./Home";
import { Page1 } from "./Page1";
import { Page1DetailA } from "./Page1DetailA";
import { Page1DetailB } from "./Page1DetailB";
import { Page2 } from "./Page2";

export default function App() {
  return (
    <BrowserRouter>
      <div className="App">
        <Link to="/">Home</Link>
        <br />
        <Link to="/page1">Page1</Link>
        <br />
        <Link to="/page2">Page2</Link>

        <Switch>
          <Route exact path="/">
            <Home />
          </Route>
      --------------------　追加　--------------------
          <Route
            path="/page1"
            render={({ match: { url } }) => (
              <Switch>
                <Route exact path={url}>
                  <Page1 />
                </Route>
                <Route path={`${url}/detailA`}>
                  <Page1DetailA />
                </Route>
                <Route path={`${url}/detailB`}>
                  <Page1DetailB />
                </Route>
              </Switch>
            )}
          >
          </Route>
    --------------------　追加　----------------------

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

```react:Page1.jsx
import { Link } from "react-router-dom";

export const Page1 = () => {
  return (
    <div>
      <h1>Page1ページです。</h1>
      <Link to="/page1/detailA">DetailA</Link>
      <br />
      <Link to="/page1/detailB">DetailB</Link>
    </div>
  );
};
```
`page1/detailA``page1/detailB`のようにネストされたページ遷移のルーティングの仕方。
`render`はデフォルトで`props`を受け取りprops内の`match`の`url`を使うことでネストされたルーティング部分は`page1`であることを保証している書き方にできる。


## ルート定義の分割
ルーティング部分を別ファイルに切り出す。

```react:App.jsx
import { BrowserRouter, Link } from "react-router-dom";

import { Router } from "./router/Router";

export default function App() {
  return (
    <BrowserRouter>
      <div className="App">
        <Link to="/">Home</Link>
        <br />
        <Link to="/page1">Page1</Link>
        <br />
        <Link to="/page2">Page2</Link>
        <Router /> 
      </div>
    </BrowserRouter>
  );
}
```

```react:Router.jsx
import { Switch, Route } from "react-router-dom";
import { Home } from "../Home";
import { Page2 } from "../Page2";
import { Page1Route } from "./Page1Route";

export const Router = () => {
  return (
    <Switch>
      <Route exact path="/">
        <Home />
      </Route>
  -----------Page1Detail部分-------------------
      <Route
        path="/page1"
        render={({ match: { url } }) => (
          <Switch>
            {Page1Route.map((route) => (
              <Route
                key={route.path}
                exact={route.exact}
                path={`${url}${route.path}`}
              >
                {route.children}
              </Route>
            ))}
          </Switch>
        )}
      ></Route>
  -------------------------------------------
      <Route path="/page2">
        <Page2 />
      </Route>
    </Switch>
  );
};
```
Page1Detail部分も別ファイルに切り出す。

```react:Page1Route.jsx
import { Page1 } from "../Page1";
import { Page1DetailA } from "../Page1DetailA";
import { Page1DetailB } from "../Page1DetailB";

export const Page1Route = [
  {
    path: "/",
    exact: true,
    children: <Page1 />
  },
  {
    path: "/detailA",
    exact: false,
    children: <Page1DetailA />
  },
  {
    path: "/detailB",
    exact: false,
    children: <Page1DetailB />
  }
];
```
`Page1Route`コンポーネントではpath、exactかどうか、レンダリングされるコンポーネントは何か、が分かるように切り出して`Router`コンポーネントで`map`を使うことで実現できる。

## URLパラメーター 
URLパラメーターはパスにIDのようなパラメーターを渡す部分。

今回は`Page２`にIDを渡すことにする。
`Page２`も`Page１`同様に別ファイルに切り出す。

```react:Router.jsx
import { Switch, Route } from "react-router-dom";
import { Home } from "../Home";
import { Page1Route } from "./Page1Route";
import { Page2Route } from "./Page2Route";

export const Router = () => {
  return (
    <Switch>
      <Route exact path="/">
        <Home />
      </Route>
      <Route
        path="/page1"
        render={({ match: { url } }) => (
          <Switch>
            {Page1Route.map((route) => (
              <Route
                key={route.path}
                exact={route.exact}
                path={`${url}${route.path}`}
              >
                {route.children}
              </Route>
            ))}
          </Switch>
        )}
      ></Route>
      <Route
        path="/page2"
        render={({ match: { url } }) => (
          <Switch>
            {Page2Route.map((route) => (
              <Route
                key={route.path}
                exact={route.exact}
                path={`${url}${route.path}`}
              >
                {route.children}
              </Route>
            ))}
          </Switch>
        )}
      ></Route>
    </Switch>
  );
};
```

```react:Page2Route.jsx
import { Page2 } from "../Page2";
import { Urlparameter } from "../UrlParameter";

export const Page2Route = [
  {
    path: "/",
    exact: true,
    children: <Page2 />
  },
  {
    path: "/:id",
    exact: false,
    children: <Urlparameter />
  }
];
```
pathの部分に`:パラメータ名`と書くことでパラメーターを受け取ることができる。
今回はIDを受け取るので`:id`とする。

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

export const Page2 = () => {
  return (
    <div>
      <h1>Page2ページです。</h1>
      <Link to="/page2/100">URL Parameter</Link>
    </div>
  );
};
```
`Link`部分に今回渡す値の100を設定しておく。

```react:UrlParameter.jsx 
import { useParams } from "react-router-dom";

export const Urlparameter = () => {
  const { id } = useParams();
  return (
    <div>
      <h1>Urlparameterページです。</h1>
      <p>パラメーターは {id} です</p>
    </div>
  );
};
```
`useParams`を使うことでパラメーターの値の受け渡しができる。

# 参考
https://reactrouter.com/web/guides/quick-start