Reactについて学んだことをまとめる（その３）

以下のUdemyの講座を受講したので、学んだことをまとめていく。

https://www.udemy.com/course/react_stepup/

## React-Router
ページ遷移を実現するのに必要。

### 環境
`react-router-dom`を`package.json`に記載し、導入する必要がある。
```
"react-router-dom": "5.2.0",
"react": "^18.3.1",
"react-dom": "^18.3.1"
```

### 基本的な使い方
```jsx
import { BrowserRouter, Link, Switch, Route } from 'react-router-dom';

import './App.css';
import { Home } from './Home';
import { Page1 } from './Page1';
import { Page2 } from './Page2';

export default function App() {
  return (
    <BrowserRouter>
      <div>
        <Link to="/">Home</Link>
        <br />
        <Link to="/page1">Page1</Link>
        <br />
        <Link to="/page2">Page2</Link>
      </div>
      <Switch>
        <Route exact path="/">
          <Home />
        </Route>
        <Route path="/page1">
          <Page1 />
        </Route>
        <Route path="/page2">
          <Page2 />
        </Route>
        <Route path="*">
          <Page404 />
        </Route>
      </Switch>
    </BrowserRouter>
  );
}
```

- `BrowserRouter`タグでページ全体を囲む。囲まれた範囲でしか機能が有効にならない。
- `Link`タグでリンクを表示し、`to`に指定されたパスがリンクをクリックした際に渡される。
- `Switch`タグの中にページ遷移設定を記載していく。
- `Route`タグで`path`に指定されたパスと一致した際の表示内容を設定する。
    - `path`に`*`を指定するとどのルートにも一致しなかった場合に表示する内容を指定できる。
    - `exact`を付加すると`path`に指定されたパスと完全一致した場合に遷移するように設定できる。
    - `render`にアロー関数を渡してその内容を描写することもできる。
    - `render`のアロー関数の引数にはPropsを使用することができ、様々な情報を受取ることができる。

```jsx
<Route path="/page1" render={() => <Page1 />}
```

```jsx
<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>
  )}
/>
```

### URLパラメータ
URLパラメータを扱う際は`Route`タグの`path`に`:ParameterName`という形式で指定する。

```jsx
<Route path="/page2/:id">
  <UrlParameter />
</Route>
```

`Link`タグでリンクをクリックした際にURLパラメーターを渡す。
```jsx
<Link to="/page2/100">URL Parameter</Link>
```

渡されたパラメーターは`useParams`を使用して受け取ることができる。
受け取る変数名は`Route`タグの`path`で指定した名前と合わせる。
```jsx
import { useParams } from 'react-router-dom';

export const UrlParameter = () => {
  const { id } = useParams();

  return (
    <div>
      <h1>UrlParameter</h1>
      <p>{id}</p>
    </div>
  );
};
```

### クエリパラメータ
`Link`タグの`to`にパスを指定する際、クエリパラメータを含める。
```jsx
<Link to="/page2/999?name=hogehoge">Query Parameter</Link>
```

渡されたクエリパラメータは`useLocation`を利用すると取り出すのが簡単になる。
`useLocation`の`search`にクエリパラメータが格納される。
`URLSearchParams`にクエリパラメータを渡すと、クエリパラメータを扱う様々な関数を利用できるようになる。
`get`メソッドで指定したkeyの値を取得することができる。

```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>
  );
};
```

### ページ間で情報を受け渡す(動作未確認)
ページ間で情報を受け渡す際は、`Link`タグの`to`にオブジェクトの形で設定を行う。
`pathname`にパスの情報を指定し、`state`にページ間で受け渡す情報を指定する。
```jsx
<Link to={{ pathname: '/page1/detailA', state: { a: "1", b: "2" }}>DetailA</Link>
```

渡された値は`useLocation`の`state`に格納されている。
```jsx
import { useLocation } from 'react-router-dom';

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

  return (
    <div>
      <h1>Page1DetailA</h1>
      <p>{state}</p>
    </div>
  );
};
```
上手く動作を確認できなかったので、別途確認する。

### Linkを使用しないページ遷移(動作未確認)
`useHistory`を使用する。
`push("URL")`で指定したURLへ遷移し、`goBack`メソッドで前の画面に遷移する。
```jsx
import { Link, useHistory } from 'react-router-dom';

export const Page1 = () => {
  const history = useHistory();

  const onClickPush = () => {
    history.push('/page1/detailA');
  };

  const onClickGoBack = () => {
    history.goBack();
  };

  return (
    <div>
      <h1>Page1</h1>
      <Link to="/page1/detailA" state={{ a: 1, b: 2 }}>
        DetailA
      </Link>
      <br />
      <Link to="/page1/detailB">DetailB</Link>
      <br />
      <button onClick={onClickPush}>Push</button>
      <button onClick={onClickGoBack}>goBack</button>
    </div>
  );
};
```
上手く動作を確認できなかったので、別途確認する。