React Routerを基礎から @yukilulu0229

## 何ができるの?

Reactで作成したSPAに、UIとURLを紐づけるためのものです。

### 参考

https://qiita.com/TMDM/items/0939ff52ab5b459303d7

thx: @TMDM 

https://reactrouter.com/en/main

https://reactrouter.com/en/main/start/tutorial

## インストール

```
npm install react-router-dom
```

## 使い方

https://zenn.dev/tomohide0102/articles/c4cae8a667ab80 

v6から書き方が微妙に変わったので注意 Switchがなくなったり

```App.jsx
import React from 'react'
import Home from "./components/Home.jsx";
import Page2 from "./components/Page2.jsx";
import Page3 from "./components/Page3.jsx";
import { BrowserRouter, Link,  Route, Routes} from "react-router-dom";

function App() {
  return (
    <div className="App">
      <section>
        <h2>React Router</h2>
        <BrowserRouter>
          <Link to="/">Home</Link>
          <Link to="/Page2">Page2</Link>
          <Link to="/Page3">Page3</Link>

          <Routes>
            <Route path="/" element={<Home />} />
            <Route path="/Page2" element={<Page2 />} />;
            <Route path="/Page3" element={<Page3 />} />
          </Routes>
        </BrowserRouter>
    </div>
  )
}

export default App

```

BrowserRouterで囲む

### Link
URLが変わる

### Routes, Router

表示したいコンテンツが変わる

## ネストする場合 (ちょっと自身がないけどやりたいことはこれで実行できた)

```App.jsx
import React from 'react'
import Home from "./components/Home.jsx";
import Page2 from "./components/Page2.jsx";
import Page3 from "./components/Page3.jsx";
import { BrowserRouter, Link,  Route, Routes} from "react-router-dom";

function App() {
  return (
    <div className="App">
      <section>
        <h2>React Router</h2>
        <BrowserRouter>
          <Link to="/">Home</Link>
          <Link to="/Page2">Page2</Link>
          <Link to="/Page3">Page3</Link>

          <Routes>
            <Route path="/" element={<Home />} />
            <Route path="/Page2" element={<Page2 />} >
              <Route path="Page2DetailA" element={<Page2DetailA />} />
              <Route path="Page2DetailB" element={<Page2DetailB />} />
            </ Route>
            <Route path="/Page3" element={<Page3 />} />
          </Routes>
        </BrowserRouter>
    </div>
  )
}

export default App

```

Routeの中にRouteを入れてあげる

```Page2.jsx
import React from 'react';
import {Link, Route, Routes} from "react-router-dom";
import Page2DetailA from "./Page2DetailA.jsx";
import Page2DetailB from "./Page2DetailB.jsx";

const Page2 = () => {
  return (
    <div>
      <h3>Page2</h3>

      <Link to="/Page2/Page2DetailA">Page2DetailA</Link>
      <br/>
      <Link to="/Page2/Page2DetailB">Page2DetailB</Link>

      <Routes>
        <Route path="Page2DetailA" element={<Page2DetailA />} />
        <Route path="Page2DetailB" element={<Page2DetailB />} />
      </Routes>
    </div>
  );
};

export default Page2;

```

Routesを作る

```Page2DetailA.jsx
import React from 'react';

const Page2DetailA = () => {
  return (
    <div>
      <h4>Page2DetailA</h4>
    </div>
  );
};

export default Page2DetailA;

```

## ルート定義の分割

/src/router/Router.jsx を作る

ルートだけを抽出して見通しをよくする


```App.jsx
import React from 'react'
import Home from "./components/Home.jsx";
import Page2 from "./components/Page2.jsx";
import Page3 from "./components/Page3.jsx";
import { BrowserRouter, Link} from "react-router-dom";
import Router from "./router/Router.jsx";

function App() {
  return (
    <div className="App">
      <section>
        <h2>React Router</h2>
        <BrowserRouter>
          <Link to="/">Home</Link>
          <Link to="/Page2">Page2</Link>
          <Link to="/Page3">Page3</Link>

          <Routes>
            <Route path="/" element={<Home />} />
            <Route path="/Page2" element={<Page2 />} >
              <Route path="Page2DetailA" element={<Page2DetailA />} />
              <Route path="Page2DetailB" element={<Page2DetailB />} />
            </ Route>
            <Route path="/Page3" element={<Page3 />} />
          </Routes>
        </BrowserRouter>
    </div>
  )
}

export default App

```


```/src/router/Router.jsx
import React from 'react';
import {Route, Routes} from "react-router-dom";
import Home from "../components/Home.jsx";
import Page2 from "../components/Page2.jsx";
import Page2DetailA from "../components/Page2DetailA.jsx";
import Page2DetailB from "../components/Page2DetailB.jsx";
import Page3 from "../components/Page3.jsx";

const Router = () => {
  return (
    <>
      <Routes>
        <Route path="/" element={<Home />} />
        <Route path="/Page2" element={<Page2 />} >
          <Route path="Page2DetailA" element={<Page2DetailA />} />
          <Route path="Page2DetailB" element={<Page2DetailB />} />
        </ Route>
        <Route path="/Page3" element={<Page3 />} />
      </Routes>
    </>
  );
};

export default Router;

```

### もっと見通しをよくする

```Router.jsx
import React from 'react';
import {Route, Routes} from "react-router-dom";
import Home from "../components/Home.jsx";
import Page2 from "../components/Page2.jsx";
import Page3 from "../components/Page3.jsx";
import {page2Routes} from "./Page2Routes.jsx";
const Router = () => {
  return (
    <>
      <Routes>
        <Route path="/" element={<Home />} />
        <Route path="/Page2" element={<Page2 />} >
          {page2Routes.map((route) => (
            <Route key={route.path} path={route.path} element={route.children} />
          ))}
        </ Route>
        <Route path="/Page3" element={<Page3 />} />
      </Routes>
    </>
  );
};

export default Router;


```

```page2Routes.jsx

import Page2DetailA from "../components/Page2DetailA.jsx";
import Page2DetailB from "../components/Page2DetailB.jsx";

export const page2Routes = [
  {
    path: "Page2DetailA",
    children: <Page2DetailA />
  },
  {
    path: "Page2DetailB",
    children: <Page2DetailB />
  }
]

```

```Page2.jsx

import React from 'react';
import {Link, Route, Routes} from "react-router-dom";
import {page2Routes} from "../router/Page2Routes.jsx";

const Page2 = () => {
  return (
    <div>
      <h3>Page2</h3>

      <Link to="/Page2/Page2DetailA">Page2DetailA</Link>
      <br/>
      <Link to="/Page2/Page2DetailB">Page2DetailB</Link>

      <Routes>
        <Route>
          {page2Routes.map((route) => (
            <Route key={route.path} path={route.path} element={route.children} />
          ))}
        </ Route>
      </Routes>
    </div>
  );
};

export default Page2;

```

## URLパラメーター

```src/router/Page3Routes.jsx

import UrlParameter from "../components/UrlParameter.jsx";

export const page3Routes = [
  {
    path: ":id", // クエリのパラメータの名前を決める
    children: <UrlParameter />
  },
]

```

セミコロンで動的に指定する
 path: ":id", // クエリのパラメータの名前を決める

```src/route/Router.jsx

import React from 'react';
import {Route, Routes} from "react-router-dom";
import Page3 from "../components/Page3.jsx";
import {page3Routes} from "./Page3Routes.jsx";
const Router = () => {
  return (
    <>
      <Routes>
        <Route path="/Page3" element={<Page3 />} >
          {page3Routes.map((route) => (
            <Route key={route.path} path={route.path} element={route.children} />
          ))}
        </ Route>
      </Routes>
    </>
  );
};

export default Router;

```

```Page3.jsx
import React from 'react';
import {Link, Route, Routes} from "react-router-dom";
import {page3Routes} from "../router/Page3Routes.jsx";

const Page3 = () => {
  return (
    <div>
      <h3>Page3</h3>

      <Link to="/Page3/100">UrlParameter: 100</Link>
      <br/>
      <Link to="/Page3/200">UrlParameter: 200</Link>

      <Routes>
        <Route>
          {page3Routes.map((route) => (
            <Route key={route.path} path={route.path} element={route.children} />
          ))}
        </ Route>
      </Routes>
    </div>
  );
};

export default Page3;

```

Linkのtoにパラメータを決める


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

const UrlParameter = () => {
  const {id} = useParams();
  return (
    <div>
      <h4>UrlParameter</h4>
      <p>idは {id} です</p>
    </div>
  );
};

export default UrlParameter;

```

useParamsでパラメーターを取得する
page3Routesで決めた名前と変数名を一致させる :id なので id

## クエリを取得する

```UrlParameter.jsx

import React from 'react';
import {useLocation} from "react-router-dom";

const UrlParameter = () => {
  const {search} = useLocation()
  const query = new URLSearchParams(search)

  return (
    <div>
      <h4>UrlParameter</h4>
      <p>パラメーターは {id} です</p>
      <p>クエリのnameは {query.get("name")} です</p>
      <p>クエリのidは {query.get("id")} です</p>
    </div>
  );
};

export default UrlParameter;

```
useLocationを使う
クエリ内のsearchで受け取る
それをURLSearchParamsで受け取る
query.get("name")やquery.get("id")
query.toString()で全部

https://developer.mozilla.org/ja/docs/Web/API/URLSearchParams


```Page3.jsx

import React from 'react';
import {Link, Route, Routes} from "react-router-dom";
import {page3Routes} from "../router/Page3Routes.jsx";

const Page3 = () => {
  return (
    <div>
      <h3>Page3</h3>
      <Link to="/Page3/200?name=foo">Query Parameter: name=foo</Link>
      <br />
      <Link to="/Page3/200?name=foo&id=400">Query Parameter: name=foo&id=400</Link>

      <Routes>
        <Route>
          {page3Routes.map((route) => (
            <Route key={route.path} path={route.path}
                   element={route.children} />
          ))}
        </ Route>
      </Routes>
    </div>
  );
};

export default Page3;

```

## stateを渡すページ遷移

https://zenn.dev/lilac/articles/c40b35fe3184da


無駄なAPIアクセスを防ぐなど方法は色々

```Page2.jsx
import React from 'react';
import {Link, Route, Routes} from "react-router-dom";
import {page2Routes} from "../router/Page2Routes.jsx";

const Page2 = () => {
  const array = [...Array(100).keys()]
  return (
    <div>
      <h3>Page2</h3>
      <Link to={"/Page2/Page2DetailA"} state={{array: array}}>Page2DetailA with state</Link>
    </div>
  );
};

export default Page2;


```

state={{array: array}で arrayの配列をstateで渡す

```Page2DetailA.jsx

import React from 'react';
import {useLocation} from "react-router-dom";

const Page2DetailA = () => {
  const {state} = useLocation()
  console.log(state)
  return (
    <div>
      <h4>Page2DetailA</h4>
    </div>
  );
};

export default Page2DetailA;


```
useLocationを使う
const {state} = useLocation() で受け取る 直切受け取るために{state}で取得してもよい

## Linkを使わないページ遷移

```Page2.jsx

import React from 'react';
import {Link, Route, Routes, useNavigate} from "react-router-dom";
import {page2Routes} from "../router/Page2Routes.jsx";

const Page2 = () => {
  const navigate = useNavigate()
  const onClickDetailA = () => {
    navigate("/Page2/Page2DetailA")
  };
  return (
    <div>
      <h3>Page2</h3>
      <button onClick={onClickDetailA}>to Page2DetailA</button>
    </div>
  );
};

export default Page2;


```
useNavigateを使う
navigate("xxx")に遷移先を記入

### 戻りたい機能の場合

```Page2DetailA.jsx
import React from 'react';
import {useLocation, useNavigate} from "react-router-dom";

const Page2DetailA = () => {
  const navigation = useNavigate()
  const onClickBack = () => {
    navigation(-1);
  };
  return (
    <div>
      <button onClick={onClickBack}>戻る</button>
    </div>
  );
};

export default Page2DetailA;

```

useNavigateを使う
navigate(-1)で一つ前の画面に戻る
数値を変えることで戻りたい画面の数を変更できる

https://maaengineerhouse.com/archives/1929

## 404ページを作成

https://stackoverflow.com/questions/67050966/how-to-build-a-404-page-with-react-router-dom-v6

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

const Page404 = () => {
  return (
    <div>
      <p>Page404</p>
      <Link to={"/"}>To TopPage</Link>
    </div>
  );
};

export default Page404;


```

```Router.jsx

import React from 'react';
import {Route, Routes} from "react-router-dom";
import Home from "../components/Home.jsx";
import Page404 from "../Page404.jsx";
const Router = () => {
  return (
    <>
      <Routes>
        <Route path="/" element={<Home />} />
        <Route path="*" element={<Page404 />} />
      </Routes>
    </>
  );
};

export default Router;


```

path="*"で設定する

これで無効なアドレスを404に飛ばせる