[React] React Router 後編

React初心者がReact Routerについて勉強した時のメモです。
後編の今回は、

- クエリパメーターの値の受け渡し
- stateを渡すページ遷移
- Linkを使わないページ遷移
- 404ページ

です。

## クエリパラメーター
クエリパラメーターとはURLの末尾ついてる`?name=hogehoge`のような部分のこと。

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

export const Page2 = () => {
  return (
    <div>
      <h1>Page2ページです。</h1>
      <Link to="/page2/100">URL Parameter</Link>
      <br />
      <Link to="/page2/100?name=hogehoge">Query Parameter</Link>
    </div>
  );
};
```

```react:Urlparameter.jsx
import { useParams, useLocation } from "react-router-dom";

export const Urlparameter = () => {
  const { id } = useParams();
  const { search } = useLocation();
  const query = new URLSearchParams(search);
  return (
    <div>
      <h1>Urlparameterページです。</h1>
      <p>パラメーターは {id} です</p>
      <p>クエリは {query.get("name")}</p>
    </div>
  );
};
```
`useLocation`を使うことでクエリパラメーターの値の受け渡しができる。
`useLocation`内の`search`という部分に`？`以降の文字列が渡ってくる。(今回の場合だと`name=hogehoge`の部分)
`search`を`URLSearchParams`メソッドの引数に渡すことで`get`というメソッドを使い`name`を指定することで`hogehoge`が取得できる。

## stateを渡すページ遷移
ページ遷移の時にstateを持たせる方法。
stateを受け渡すメリットは、APIでつぶやきなどの一覧ページを取得し、取得した情報(state)を持ってつぶやき詳細ページに遷移すればもう一度APIを呼ぶ必要なく情報(state)を受け渡せる。

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

export const Page1 = () => {
 
  //-------- 渡したい情報 --------------
  const arr = [...Array(100).keys()];
  console.log(arr);
 //----------------------------------

  return (
    <div>
      <h1>Page1ページです。</h1>
      <Link to={{ pathname: "/page1/detailA", state: arr }}>DetailA</Link>
      <br />
      <Link to="/page1/detailB">DetailB</Link>
    </div>
  );
};
```
`Link`の部分に`pathname`と書き、パスと`state`を持たせる。

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

export const Page1DetailA = () => {

  const { state } = useLocation();
  console.log(state);

  return (
    <div>
      <h1>Page1DetailAページです。</h1>
    </div>
  );
};
```
`useLocation`を使うことで渡ってきた`state`を取得できる。
## Linkを使わないページ遷移
JavaScript側でページ遷移する方法。
例えば、ボタンを押した後のページ遷移や、投稿などの処理が終わった後に起きるページ遷移。

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

export const Page1 = () => {
  const arr = [...Array(100).keys()];
  console.log(arr);

  const history = useHistory();
  const onClickDetailA = () => history.push("/page1/detailA");

  return (
    <div>
      <h1>Page1ページです。</h1>
      <Link to={{ pathname: "/page1/detailA", state: arr }}>DetailA</Link>
      <br />
      <Link to="/page1/detailB">DetailB</Link>
      <br />
      <button onClick={onClickDetailA}>DetailA</button>
    </div>
  );
};
```
`useHistory`を使う。
`history.push(リンクのパス)`とすることで画面遷移できる。
今回の場合はボタンを押したら、`/page1/detailA`に画面遷移する。

```react:Page1DetailA
import { useLocation, useHistory } from "react-router-dom";

export const Page1DetailA = () => {
  const { state } = useLocation();
  console.log(state);

  const history = useHistory();
  const onClickBack = () => history.goBack();

  return (
    <div>
      <h1>Page1DetailAページです。</h1>
      <br />
      <button onClick={onClickBack}>戻る</button>
    </div>
  );
};
```
`history.goBack()`とすることでブラウザの戻るボタンと同じような戻る画面遷移ができる。

## 404ページ
存在しないページを作成しておく。

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

export const Page404 = () => {
  return (
    <div>
      <h1>ページが見つかりません</h1>
      <Link to="/">TOPに戻る</Link>
    </div>
  );
};
```

```react:Router
import { Switch, Route } from "react-router-dom";
import { Home } from "../Home";
import { Page404 } from "../Page404";
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>
  ------- 追加 -----------
      <Route to="*">
        <Page404 />
      </Route>
 ------------------------
    </Switch>
  );
};
```
追加した部分のようにすることでどのページにも一致しない時に`Page404`がレンダリングされる。

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