React Router とは (v6)

## react-routerとは
Reactアプリケーションでルーティング（ページ遷移）を実現するためのライブラリです。ルーティングとは、ユーザーが異なるURLにアクセスしたとき、特定のコンポーネントを表示する仕組みのことです。SPAにおいて、React Routerを使うとページ全体を再読み込みすることなく、URLに応じてコンポーネントを切り替えることができます。

## 基本的な仕組み
### <font color="#66FF66">BrowserRouter</font>
まず、`Router`について簡単に説明します。`Router`は、アプリケーション全体にルーティング機能を提供するコンポーネントです。ルートの履歴管理や、URLの変更に基づいてどのコンポーネントを表示するか決定するために必要です。

`BrowserRouter`は`React Router`のコンポーネントの1つで、Reactアプリケーションにルーティング機能を提供します。`Router`自体には複数の種類がありますが、最も一般的なのが`BrowserRouter`です。

主な役割は、アプリケーション全体にルーティングのコンテキストを提供し、アプリが異なるURLにアクセスしたとき対応するコンポーネントを表示することです。 HTMLの`Wrapper`のようなものだと認識しています。

具体的に、HTML5の [history API](https://developer.mozilla.org/ja/docs/Web/API/History) (戻る、進むなどの操作履歴の管理)を利用してURLを管理し、ページの再読み込みなしにナビゲーションを実現します。

また、`<Router>`の中に別の`<Router>` レンダリングすることはできません。`App.js`を`<BrowserRouter>`で囲った場合、それ以上`<BrowserRouter>`は不要です(※重要)

```react:index.jsx
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>
);
```

### <font color="#66FF66">Routes</font>
`Routes`は、複数のルートをグループ化するためのコンポーネントです。URLに応じて表示するルート (`path`) を決定し、`Route`コンポーネントをレンダリングします。

```react
// プロパティの詳細は後ほど記述します
<Routes>
  <Route path="/" element={<Home />} />
  <Route path="/about" element={<About />} />
</Routes>
```

### <font color="#66FF66">Route</font>
`Route`は、パスに対してどのコンポーネントを表示するか定義するコンポーネントです。`Route`はURLパス（`path`）と表示するコンポーネント（`element`）を関連付けます。
```react
  <Route path="/" element={<Home />} />
```

### 基本的な仕組み　まとめ

1. **`Router(BrowserRouter)`** でアプリケーション全体のルーティング機能を有効にします。
2. **`Routes`** でルートのグループを作成し、アプリケーション全体のルートを定義します。
3. **`Route`** で個別のパスに対して対応するコンポーネントを紐づけます。

では実際にルーティングしていきましょう。


## react-router-domをインストール
![スクリーンショット 2024-10-09 19.12.14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/668222/3fb0ed31-6941-a2db-f37d-27a6e24292d7.png)
[codesandbox](https://codesandbox.io)を使用しています。
```
$ npm i react-router-dom
```

以下を作成しました。
```
./components
    - Home.jsx
    - Page1.jsx
    - Page2.jsx
```

## 基本ルーティング

[BrowserRouter](###BrowserRouter)が基本的なルーティングです。
`App.jsx`は以下の記述になります。
```App.jsx
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>
  );
}
```

```Home.jsx
// Page1, Page2も同様に作成します
export default function Home() {
  return (
    <div>
      <h1>HOME</h1>
    </div>
  );
}
```
これでルーティングされました。
![スクリーンショット 2024-10-12 11.15.00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/668222/868b8ddd-ba20-cce9-af6d-338a67b1fbaf.png)

### <font color="#33FF00">Linkコンポーネント , toプロパティ</font>
ページ間のナビゲーションを行うために使用される重要なコンポーネントです。`<a>`タグのようにURLにリンクを提供しますが、ページの再読み込みを発生させずにクライアントサイドでのルーティングを実現します。SPAの特性を活かし、スムーズなページ遷移ができるのです。

Linkコンポーネントは`to`プロパティを使って移動先のURLを指定します。`href`属性に似ていますが、`React Router`ではページリロードなしで指定パスに遷移します。

```react
<Link to="/">HOME</Link>
<Link to="page1">PAGE1</Link>
```

### <font color="#33FF00">path , element プロパティ</font>
`Route`コンポーネントでは、`path`と`element` という2つのプロパティが重要な役割を果たします。`path`は、URLパス（ルート）を指定するために使用。

もう１つの`element`は、`path`に対応するコンポーネントを表示するために使用します。表示したいコンポーネントをJSX形式で渡すのです。通常、HTMLタグやカスタムコンポーネントが設定されます。
```react
<Route path="/about" element={<About />} />
```
ここまでが基礎的なルーティングです。
他のルーティングも見ていきましょう。

## ネストされたページ遷移
Page1を親とし、子ページ Page1DetailsA.jsx と Page1DetailsB.jsx を作成します。
```
./components
    - Home.jsx
    - Page1.jsx
    - Page1DetailsA
    - Page1DetailsB
    - Page2.jsx
```

```Page1.jsx
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>
  );
}
```
```Page1DetailsA.jsx
import { Link } from "react-router-dom";

export default function Page1DetailsA() {
  return (
    <div>
      <h1>Page1DetailsA</h1>
      <Link to="/page1/detailsA">Page1DetailsA</Link>
      <br />
      <Link to="/page1/detailsB">Page1DetailsB</Link>
    </div>
  );
}
```
Page1.jsx からコピーして書き換えただけです。 Page1DetailsB.jsx も同じように操作します。 
```App.jsx
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 element={<Page1 />} /> {/*index*/}
          <Route path="/page1/detailsA" element={<Page1DetailsA />} /> {/*追加*/}
          <Route path="/page1/detailsB" element={<Page1DetailsB />} /> {/*追加*/}
        </Route>
        <Route path="/page2" element={<Page2 />} />
      </Routes>
    </div>
  );
}
```
![スクリーンショット 2024-10-12 12.14.05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/668222/35e2afe1-2812-4100-f85b-003bfe16ca62.png)


App.js の記述を説明します。まず、ネスト化しているコンポーネントを `<Route>` で囲う必要があります。
```jsx
<Route path="/page1">
...
</Route>
```
Page1のRouteコンポーネントを `index` 属性に設定します。
```jsx
<Route index element={<Page1 />} />
```
### <font color="#33FF00">indexプロパティ</font>
親ルートにアクセスしたとき、子ルートを指定しない場合に表示される「デフォルトのページ」を定義します。

通常、ルートは`path`プロパティでURLを指定しますが、`index`を使う場合は`path`を指定しません。代わりに、その親ルートが呼び出されたときに表示される「初期コンテンツ」として設定されます。

indexの指定は `true` , `false` で使われることがありますが、実際にはindexを指定するだけで「true」と同じ意味になります。`index={true}` と書く必要はなく、単に`index`と書けば、「このルートはインデックスルート」という意味です。

なお、`index={false}`は基本書きません。`index`ルートにしたくない場合、そのルートに`path`を指定して通常のルートとして扱います。


## URLパラメーターを使う
componentsに UrlParameter.jsx を作成します。
```UrlParameter.jsx
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>
  );
}
```
```Page2.jsx
import { Link } from "react-router-dom";

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

```
```App.jsx
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 element={<Page1 />} />
          <Route path="/page1/detailsA" element={<Page1DetailsA />} />
          <Route path="/page1/detailsB" element={<Page1DetailsB />} />
        </Route>
        <Route path="/page2">
          <Route index element={<Page2 />} /> {/*index*/}
          <Route path=":id" element={<UrlParameter />} /> {/*追加*/}
        </Route>
      </Routes>
    </div>
  );
}
```
![スクリーンショット 2024-10-12 18.40.15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/668222/e1d9c236-e752-83a9-80f1-18e1eed5efb4.png)

### <font color="#33FF00">useParams</font>
URLに含まれる「動的なパラメータ」にアクセスするため使用されます。ユーザーIDなどを含むURL`/users/:id`を定義し、そのIDに基づいたユーザー情報を表示したい場合などです。
```jsx
// const { 値 } と記述する。なんでも可
const { id } = useParams();

// 今回は { id } なので
// コンポーネントで取得する値は :id となる。 
// :値 と記述する
<Route path=":id" element={<UrlParameter />} />
```



## クエリパラメータを使う
components内に QueryParameter.jsx を作成します。
```QueryParameter.jsx
import { useSearchParams } from "react-router-dom";

export const QueryParameter = () => {
  const [searchParams, setSearchParams] = useSearchParams();
  // .getにてクエリパラメータに設定した値(name)を取得する。
  const name = searchParams.get("name");
  return (
    <div>
      <h1>QueryParameter</h1>
      <p>Query parameter is {name}</p>
    </div>
  );
};
```
```Page2.jsx
import { Link } from "react-router-dom";

export const Page2 = () => {
  return (
    <div>
      <h1>PAGE2</h1>
      <Link to="/page2/10">UrlParameter</Link>
      <br />
      <Link to="/page2/query?name=hello">QueryParameter</Link> {/*nameに値を設定*/}
    </div>
  );
};
```
```App.jsx
// ...略
import { QueryParameter } from "./components/QueryParameter"; // 追加

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 />} />
        {/*page1*/}
        <Route path="/page2">
          <Route index element={<Page2 />} />
          <Route path=":id" element={<UrlParameter />} />
          <Route path="/page2/query" element={<QueryParameter />} /> {/*追加*/}
        </Route>
      </Routes>
    </div>
  );
}
```
![スクリーンショット 2024-10-14 19.21.30.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/668222/7614ee71-d4e3-42f5-f3ed-03b3e429a102.png)

### <font color="#33FF00">useSearchParams</font>
URLのクエリパラメータを取得したり、変更するために使います。

例えば「検索機能」
検索結果の絞り込みやフィルタ条件をURLに含めて保持したいときに便利です。URLに検索条件を含めることで、ページをリロードしても同じ条件で結果が表示されます。

他にも「フィルタリング」
商品一覧pageや記事一覧pageで、カテゴリ・価格帯などのフィルタを設定する際に使います。フィルタ状態をURLに保存することで、ユーザーがリロードしてもそのフィルタ状態を保持できます。

```jsx
...
// 基礎的な値を取得する
const [searchParams, setSearchParams] = useSearchParams();

  // クエリパラメータ "category" の値を取得する
  const category = searchParams.get("category");

  // クエリパラメータ "page" の値を取得する
  const page = searchParams.get("page");

  const handleCategoryChange = (newCategory) => {
    // クエリパラメータを設定・更新する
    setSearchParams({ category: newCategory, page: "1" }); // 新しいカテゴリを設定し、ページ番号をリセット
  };

  return (
    <div>
      <h1>Current Category: {category}</h1>
      <h2>Current Page: {page}</h2>

      <button onClick={() => handleCategoryChange("electronics")}>
        Show Electronics
      </button>
      <button onClick={() => handleCategoryChange("books")}>
        Show Books
      </button>
    </div>
  );
}
```

## 404ページ（Not Found）
404ページ（Not Found）を作るには、存在しないURLへアクセスされたときに表示されるコンポーネントを定義します。そのため、`path`プロパティにワイルドカードである`*`を使用します。`*`は指定されたルート以外のすべてのURLにマッチするため、存在しないページにアクセスされたときに404ページを表示できます。
```App.jsx
import { Routes, Route, Link } from "react-router-dom";
import Home from "./components/Home";
import NotFound from "./NotFound"; // 追加

export default function App() {
  return (
    <div className="App">
      <Link to="/">HOME</Link>

      <Routes>
        <Route path="/" element={<Home />} />
        <Route path="*" element={<NotFound />} /> {/*追加*/}
      </Routes>
    </div>
  );
}

```
```NotFound.jsx
export default function NotFound() {
  return (
    <div>
      <h1>404: Page Not Found</h1>
    </div>
  );
}

```
![スクリーンショット 2024-10-12 10.47.18.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/668222/423e289b-78ed-665e-0b82-1eb6e422b663.png)