【React備忘録】React Router v6のルーティング

# <font color="green">◆ 使用環境</font>

<br>

オンラインエディタ`「code sandbox」`を使用。

バージョンはそれぞれ以下の通り。

<br>

![スクリーンショット 2023-07-07 11.47.59.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/754263/d1088871-d8a9-2fd9-671f-b3ceef9ae436.png)


<br>

# <font color="green">◆ 基本ルーティング</font>

## ① BrowserRouterの設定

index.jsで、`react-router-dom`の`BrowserRouter`コンポーネントをインポートし、
App.jsを囲む。<font color="red">（必須設定）</font>

<br>

```react
import { StrictMode } from "react";
import { createRoot } from "react-dom/client";
import { BrowserRouter } from "react-router-dom";

import App from "./App";

const rootElement = document.getElementById("root");
const root = createRoot(rootElement);

root.render(
  <StrictMode>
    <BrowserRouter>
      <App />
    </BrowserRouter>
  </StrictMode>
);

```

<br>

## ② ルーティング設定

### ・ コンポーネントの設定

![スクリーンショット 2023-07-07 12.07.35.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/754263/95990704-2429-c60c-3b3b-0916b28aaa03.png)

<br>

**Source**

```react
// Home.jsx
export default function Home() {
  return (
    <div>
      <h1>HOME</h1>
    </div>
  );
}

// Page1.jsx
export default function Page1() {
  return (
    <div>
      <h1>PAGE1</h1>
    </div>
  );
}

// Page2.jsx
export default function Page2() {
  return (
    <div>
      <h1>PAGE2</h1>
    </div>
  );
}
```

<br>

### ・ App.jsでルーティング

<br>

**Source**

```react
import "./styles.css";
import { Routes, Route, Link } from "react-router-dom";
import Home from "./components/Home";
import Page1 from "./components/Page1";
import Page2 from "./components/Page2";

export default function App() {
  return (
    <div className="App">
      <Link to="/">HOME</Link>
      <br />
      <Link to="page1">PAGE1</Link>
      <br />
      <Link to="page2">PAGE2</Link>

      <Routes>
        <Route path="/" element={<Home />} />
        <Route path="/page1" element={<Page1 />} />
        <Route path="/page2" element={<Page2 />} />
      </Routes>
    </div>
  );
}
```

<br>

### 【機能の解説】

#### 【 Link 】
HTMLのaタグ。`to=""`で飛ばすパスを設定するコンポーネント。
#### 【 Routes 】
Linkで設定したパスごとに表示するルーティングの出しわけを行うためのコンポーネント。
#### 【 Route 】
ルーティングで表示したいコンポーネントとそのパスを設定するコンポーネント。

<br>

ロジックとしては、

**①Linkタグでパスを飛ばす**

**②Routesが選別**

**②Routeで設定したパスに該当するコンポーネントが表示される**

という流れ。

<br>
<br>

# <font color="green">◆ ルーティングのネスト化</font>

Page1を親ページとして、子ページ`Page1DetailsA`と`Page1DetailsB`を用意する。

<br>

![スクリーンショット 2023-07-08 2.16.47.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/754263/9db9faca-3c2a-a05b-82a8-54bd79df8043.png)

このコンポーネント内にさらにコンポーネントがある状態を`ネスト`という。
このネスト化されたページを表示するには以下の設定が必要。

<br>
<br>

## ① 子コンポーネントのページのパスを飛ばす用のLinkを設定

**Page1.jsx**

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

export default function Page1() {
  return (
    <div>
      <h1>PAGE1</h1>
      <Link to="/page1/detailsA">Page1DetailsA</Link>
      <br />
      <Link to="/page1/detailsB">Page1DetailsB</Link>
    </div>
  );
}
```

<br>

## ② ルーティング設定

**App.jsx**

```react
import "./styles.css";
import { Routes, Route, Link } from "react-router-dom";
import Home from "./components/Home";
import Page1 from "./components/Page1";
import Page2 from "./components/Page2";
import Page1DetailsA from "./components/Page1DetailsA";
import Page1DetailsB from "./components/Page1DetailsB";

export default function App() {
  return (
    <div className="App">
      <Link to="/">HOME</Link>
      <br />
      <Link to="page1">PAGE1</Link>
      <br />
      <Link to="page2">PAGE2</Link>

      <Routes>
        <Route path="/" element={<Home />} />
        <Route path="/page1">
          <Route index={true} element={<Page1 />} />
          <Route path="/page1/detailsA" element={<Page1DetailsA />} />
          <Route path="/page1/detailsB" element={<Page1DetailsB />} />
        </Route>
        <Route path="/page2" element={<Page2 />} />
      </Routes>
    </div>
  );
}

```

### ・ ポイント

**ネスト化しているコンポーネントをRouteコンポーネントで囲う**

```react
<Route path="/page1">
...
</Route>
```

<br>

**Page1コンポーネントを表示するRouteコンポーネントのindex属性を`true`に**

```react
<Route path="/page1">
    <Route index={true} element={<Page1 />} />
</Route>
```

<br>

**子ページのコンポーネントを設定**

```react
<Route path="/page1">
    <Route index={true} element={<Page1 />} />
    <Route path="/page1/detailsA" element={<Page1DetailsA />} />
    <Route path="/page1/detailsB" element={<Page1DetailsB />} />
</Route>
```

<br>
<br>

# <font color="green">◆ URLパラメータを取得</font>

URLに設定したパラメータを取得する方法は以下の通り。

<br>

## ① コンポーネント作成

**UrlParameter.jsx**

```react
import { useParams } from "react-router-dom";

export default function UrlParameter() {
  const { id } = useParams();

  return (
    <div>
      <h1>PAGE2</h1>
      <p>URL PARAMETER is {id}</p>
    </div>
  );
}
```

**ポイント**

<font color="red">**useParams**</font>という関数を利用することで、パラメータを取得することが可能になる。

<br>

## ②　親コンポーネントでリンク設定

**Page2.jsx**

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

export default function Page2() {
  return (
    <div>
      <h1>PAGE2</h1>
       // パラメータで100を渡す
      <Link to="/page2/100">URL Parameter</Link>
    </div>
  );
}

```

<br>

# ③　App.jsでルーテング設定

**App.jsx**

```react
import "./styles.css";
import { Routes, Route, Link } from "react-router-dom";
import Home from "./components/Home";
import Page1 from "./components/Page1";
import Page2 from "./components/Page2";
import Page1DetailsA from "./components/Page1DetailsA";
import Page1DetailsB from "./components/Page1DetailsB";
import UrlParameter from "./components/UrlParameter";

export default function App() {
  return (
    <div className="App">
      <Link to="/">HOME</Link>
      <br />
      <Link to="page1">PAGE1</Link>
      <br />
      <Link to="page2">PAGE2</Link>

      <Routes>
        <Route path="/" element={<Home />} />
        <Route path="/page1">
          <Route index={true} element={<Page1 />} />
          <Route path="/page1/detailsA" element={<Page1DetailsA />} />
          <Route path="/page1/detailsB" element={<Page1DetailsB />} />
        </Route>
        <Route path="/page2">
          <Route index={true} element={<Page2 />} />
          <Route path=":id" element={<UrlParameter />} />
        </Route>
      </Routes>
    </div>
  );
}
```

<br>

**ポイント**

<font color="red">**:値**</font>とpathに設定することで、パラメータとして値が設定されるようになる。
今回は`id`として設定したため、`UrlParameter`コンポーネントで取得する値もidということになる。

```react
const { id } = useParams();
```


<br>
<br>

# <font color="green">◆ クエリパラメータの取得</font>

## ①クエリパラメータ取得用コンポーネントの作成

**・ QueryParameter.jsx**

```react
import { useSearchParams } from "react-router-dom";

export const QueryParameter = () => {
  const [searchParams, setSearchParams] = useSearchParams();
  const name = searchParams.get("name");
  return (
    <div>
      <h1>QueryParameter</h1>
      <p>Query parameter is {name}</p>
    </div>
  );
};
```

<br>

**ポイント**

<font color="red">**useSearchParams**</font>という関数を利用する。
`searchParams`の`get`メソッドを利用することで、クエリパラメータに設定した値を取得する。

<br>

## ②親コンポーネントから呼び出し

今回はPage2コンポーネントから呼び出し、クエリパラメータを取得。

**・Page2.jsx**

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

export const Page2 = () => {
  return (
    <div>
      <h1>Page2のページ</h1>
      <Link to="/page2/100">UrlParameter</Link>
      <br />
      <Link to="/page2/query?name=hello">QueryParameter</Link>
    </div>
  );
};
```

`?name=hello`でnameに値を設定。


<br>

## ③App.jsでルーティング設定

**・ App.jsx**

```react
<Route path="/page2">
    <Route index={true} element={<Page2 />} />
    <Route path=":id" element={<UrlParameter />} />
    <Route path="/page2/query" element={<QueryParameter />} />
</Route>
```

<br>
<br>

# <font color="green">◆ stateの取得</font>

子コンポーネントに対し、変数の値を渡す方法。

<br>

## ①stateを受け取るコンポーネントの設定

**・Page1DetailAコンポーネント**

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

export const Page1DetailA = () => {
  const { state } = useLocation();
  return (
    <div>
      <h1>Page1DetailAのページ</h1>
      {state != null ? (
        <ul>
          {state.map((arr) => {
            return <li key="arr">{arr}</li>;
          })}
        </ul>
      ) : (
        ""
      )}
    </div>
  );
};
```

**ポイント**

<font color="red">**useLocation**</font>関数を使用し、`state`を取得する。

今回はstateに配列を渡し、配列分リストを表示する想定でコードを記入。

<br>

## ②親コンポーネントからstateを受け渡し

**Page1.jsx**

```react
import { Link, useNavigate } from "react-router-dom";

export const Page1 = () => {
  const arr = [...Array(10).keys()];
  return (
    <div>
      <h1>Page1のページ</h1>
      <Link to="/page1/detailA" state={arr}>
        DetalilA
      </Link>
      <br />
      <Link to="/page1/detailB">DetalilB</Link>
    </div>
  );
};
```

<br>

**ポイント**

Linkコンポーネントに対し、<font color="red">**state={}**</font>で受け渡す変数を設定する。

結果は以下の通り。

![スクリーンショット 2023-07-08 16.26.36.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/754263/f1f26381-5b11-5a46-7115-095396a5cb24.png)

<br>
<br>

# <font color="green">◆ Linkコンポーネントを使用しないページ遷移</font>


Linkコンポーネントを使用せずに遷移する場合には、以下の手順で設定する。

今回の例では、ボタンを押したら遷移することを想定。


## navigate関数を使用

<font color="red">**useNavigate**</font>関数を使用し、遷移するページを設定。

```react
import { useNavigate } from "react-router-dom";

export const Page1 = () => {
  const navigate = useNavigate();
  return (
    <div>
      <h1>Page1のページ</h1>
      <button onClick={() => navigate("/page1/detailA")}>DetailA</button>
      <br />
      <Link to="/page1/detailB">DetalilB</Link>
    </div>
  );
};
```
この設定でLinkコンポーネントと同じようにページ遷移が可能。

<br>
<br>

# <font color="green">◆ 404ページの作成</font>

存在しないリンクにアクセスした場合のページ（４０４ページ）の作成は以下の通り。

## ① コンポーネントの作成

**NotFound.jsx**

```react
export const NotFound = () => {
  return <p>存在しないページです</p>;
};
```

<br>

## ② ルーティングの設定

**App.jsx**

```react
import { NotFound } from "../NotFound";

export const Router = () => {
  return (
    <Routes>
      <Route path="*" element={<NotFound />} />
    </Routes>
  );
};
```

<br>

**ポイント**

Routeコンポーネントのpathを`*（アスタリスク）`で設定する。