【React】react-router-dom v6の導入方法と使い方



<!-- 各チャプター -->
# インストール
npmコマンドを使用してパッケージをインストールします。
```bash
npm i -S react-router-dom
```
`npm i`は、`npm install`のエイリアス（別名）で、パッケージをインストールするコマンドです。

`-S`オプションは`--save`のショートカットで、このオプションをつけることで`package.json`に記録できます。`package.json`に記録しておくことで、他の人が`npm install`を実行した時に依存パッケージとしてインストールさせることができます。

# ルーティングを設定
`src/index.js`ファイルの`<App />`を`<BrowserRouter />`でラップします。
`<BrowserRouter />`は、アプリケーションにルーティング機能を提供するコンポーネントです。

```react
// src/index.js
import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';
import { BrowserRouter } from 'react-router-dom';

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
  <React.StrictMode>
    <BrowserRouter>
      <App />
    </BrowserRouter>
  </React.StrictMode>
);

reportWebVitals();
```
次に、`src/App.js`で各ページのコンポーネント（今回は`<Home />`と`<RouteRouterTest />`）と`Route, Routes`をインポートします。`Routes`コンポーネントでラップされた`Route`コンポーネントにURLと遷移先コンポーネントを記述します。

```react
// src/App.js
// react-router-dom v6
import './App.css';
import { Route, Routes } from 'react-router-dom';
import Home from './pages/Home';
import RouterTest from './pages/RouterTest';

function App() {
  return (
    <Routes>
      <Route path='/' element={<Home />} />
      <Route path="/router/test" element={<RouterTest />} />
    </Routes>
  );
}

export default App;
```

v5以前は`Switch`コンポーネントにラップされた`Route`コンポーネントでURLとコンポーネントの対応を決めていたので、混同しないように気を付けましょう。慣れ親しんだ`Switch`を使うと下記のエラーが出ます。

```bash
ERROR in ./src/App.js 20:12-18
export 'Switch' (imported as 'Switch') was not found in 'react-router-dom'
```

## 【参考】

<details><summary>v5の書き方</summary>

```react
// src/App.js
// react-router-dom v5
import './App.css';
import { Route, Switch } from 'react-router-dom';
import Home from './pages/Home';
import RouterTest from './pages/RouterTest';

function App() {
  return (
    <Switch>
      <Route path="/" exact component={<Home />} />
      <Route path="/router/test" exact component={<RouterTest />} />
    </Switch>
  );
}

export default App;

```

</details>

# Linkコンポーネントでの画面遷移

ルーティングが設定されたURLを`Link`コンポーネントの`to`に指定すると指定のコンポーネントへのリンクを作成できます。

```react
<Link to="/router/test">RouterTestのページへ</Link>
```

# useNavigateによる画面遷移
`useNavigate` Hookを利用することで、関数内で画面遷移処理を入れることができます。v5の`useHistory`と似ています。

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

const Home = () => {
    const navigate = useNavigate();
    return (
        <div>
            <div onClick={() => {navigate("/router/test")}}>
                RouterTestページへ
            </div>
        </div>
    )
}

export default Home;
```

v6で`useHistory`を使おうとすると、下記のエラーが出ます。
```bash
ERROR in ./src/pages/Home.jsx 29:10-20
export 'useHistory' (imported as 'useHistory') was not found in 'react-router-dom'
```

# 【おまけ】~window.location.hrefとの違い~
`react-router-dom`を使う代わりに`window.location.href="url"`を使えば良くない？と思った方へ。私も最初同じことを思いました。しかし、二つの遷移方法には違いがあります。

`App.js`に、ボタンと、ボタンが押された回数をステートで表示する機能を持ったヘッダーを追加して実験してみます。

<details><summary>App.js（クリックでオープン）</summary>

```react
import { useState } from 'react';
import './App.css';
import { Route, Routes, BrowserRouter } from 'react-router-dom';
import Home from './pages/Home';
import RouterTest1 from './pages/RouterTest1';
import RouterTest2 from './pages/RouterTest2';
import RouterTest3 from './pages/RouterTest3';

function App() {
  const [count, setCount] = useState(0);
  return (
    <BrowserRouter>
      <header className="App-header">
        <div>{count}</div>
        <button onClick={() => setCount((prev) => prev+1)}>
            +ボタン
        </button>
    </header>
      <Routes>
        <Route path='/' element={<Home />} />
        <Route path="/router/test/1" element={<RouterTest1 />} />
        <Route path="/router/test/2" element={<RouterTest2 />} />
        <Route path="/router/test/3" element={<RouterTest3 />} />
      </Routes>
    </BrowserRouter>
  );
}

export default App;
```
</details>

<details><summary>Home.jsx（クリックでオープン）</summary>

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

const Home = () => {
    const navigate = useNavigate();

    return (
        <div className="App">
            <button onClick={() => {
                window.location.href="/router/test/1"
            }}>
                1ページへ（window.location.hrefを利用）
            </button>
            <button>
                <Link to="/router/test/2"><span>2ページへ（Linkコンポーネントを利用）</span></Link>
            </button>
            <button onClick={() => {
                navigate("/router/test/3");
            }}>
                3ページへ（useNavigateを利用）
            </button>
        </div>
    )
}

export default Home;
```
</details>

**`window.location.href="url"`を使って遷移** 
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2885419/310957a3-bca0-c688-7da6-254706fe1fdb.png)

**`react-router-dom`を使って遷移（Linkコンポーネント）** 
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2885419/8d3cd259-c725-4dda-1e7f-da3d00b898ce.png)

**`react-router-dom`を使って遷移（useNavigate）** 
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2885419/f1adcfce-f1b1-6d92-6293-91605bf625d9.png)


`window.location.href="url"`を使って遷移した場合、ページが再読み込みされることでステートが初期化さています。一方、`react-router-dom`を使うとページを再読み込みすることなく画面遷移を行うためステートが維持されていることが確認できます。

ステートを維持したかったり余計なAPI呼び出しを行いたくなかったりするときは`react-router-dom`を使い、ログアウト処理などを行って一度ページを再読み込みしたい場合は`window.location.href="url"`を使うのが良いでしょう。



# 参考文献

https://reffect.co.jp/react/react-router-6#i-2

https://www.tohoho-web.com/ex/npm.html

https://qiita.com/kazufoot21/items/635e4ff8e6b34f026c17