Reactを基本からまとめてみた【11】【React Router ①】


##React Router とは

#####公式サイト
[REACT TRAINING / REACT ROUTER](https://reactrouter.com/core/guides/quick-start)

『React Router』は複数のページを持つReactアプリケーションを構築する際に利用されるライブラリ。複数のページが存在するということはブラウザからアクセスする為のURLが複数存在する。レイアウトなどの共通部分もあるがページ毎に異なるコンポーネントで構成されている為、URLとコンポーネントを紐づける役割が必要となる。その役割を担うのが『React Router』である。『React Router』を利用することでブラウザからURLの/aboutにアクセスするとAboutコンポーネントの内容を表示、別のURLである/contactにアクセスするとContactコンポーネントの内容を表示させるといったことが可能になる。
また通常のHTMLでのページ間の移動ではページを移動する度にブラウザからサーバにリクエストを送り、サーバからHTMLを受け取りページ全体を描写するためページ全体のリロードが必要となる。『React Router』を利用した場合はページ間の移動毎にページ全体のリロードを行うのではなくJavaScriptでページ内の更新が必要な箇所のみ更新が行われる為ページ全体のリロードを行う必要がなくなりSPA(シングルページアプリケーション）としてスムーズにページ移動を行うことができる。

##React Routerのインストール
Reactのプロジェクトのインストールが完了したら、react-router-domのインストールを行う。

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

react-router も必要になるが、react-router-dom の依存関係にあるので、一緒に追加。

##ルーティングの設定
####1.ルーティングの設定を行う前にコンポーネントの作成を行う。

http://localhost:3000/ にアクセスした場合にはHomeコンポーネント、/aboutページにアクセスした場合にAboutコンポーネント、/contactページにアクセスしたい場合にContactコンポーネントが表示されるようにApp.jsにコンポーネントを追加する。

```App.js
function App() {
  return (
    <div>
      <h1>Hello React Router</h1>
    </div>
  );
}

function Home() {
  return <h2>Home</h2>;
}
function About() {
  return <h2>About</h2>;
}
function Contact() {
  return <h2>Contact</h2>;
}
export default App;
```

####2.はじめてのルーティング設定を行う。
① 追加したコンポーネントをルーティング機能を使って表示させるためにはreact-router-domからBrowserRouter, Routeコンポーネントをimportする。

```App.js
import { BrowserRouter, Route } from 'react-router-dom';
function App() {
//略
```

②importしたBrowserRouterコンポーネントで全体を包み、BrowerRouterコンポーネントの中ではRouteコンポーネントを使ってルーティングを定義する。Routeのpathに/(ルート)を指定することで、/(ルート)にアクセスするとHomeコンポーネントの内容が表示される。

```App.js
import { BrowserRouter, Route } from 'react-router-dom';
function App() {
  return (
    <BrowserRouter>
      <h1>Hello React Router</h1>
      <Route path="/">
        <Home />
      </Route>
    </BrowserRouter>
  );
}
```

③Routeコンポーネントの子要素としてHomeコンポーネントを設定しているがcomponent propsを使って以下のように設定することも可能。

```App.js
import { BrowserRouter, Route } from 'react-router-dom';
function App() {
  return (
    <BrowserRouter>
      <h1>Hello React Router</h1>
      <Route path="/" component={Home} />
    </BrowserRouter>
  );
}
```

④ Homeコンポーネントを表示できたのでAboutコンポーネント, Contactページも追加。

```App.js
import { BrowserRouter, Route } from 'react-router-dom';
function App() {
  return (
    <BrowserRouter>
      <h1>Hello React Router</h1>
      <Route path="/">
        <Home />
      </Route>
      <Route path="/about">
        <About />
      </Route>
      <Route path="/contact">
        <Contact />
      </Route>
    </BrowserRouter>
  );
}
```

##exactの設定
/about, /contactにアクセス時に表示されている内容から考えると/aboutにアクセスした時には”/”も”/about”に含まれる為”/”に対応しているHomeコンポーネントも表示される。この問題を解決する為にRouteコンポーネントにpropsのexactを設定する。

```
<BrowserRouter>
  <h1>Hello React Router</h1>
  <Route exact path="/">
    <Home />
  </Route>
  <Route path="/about">
    <About />
  </Route>
  <Route path="/contact">
    <Contact />
  </Route>
</BrowserRouter>
```

exactを設定後に再度/aboutにアクセスするとAboutコンポーネントの中身のみ表示されることが確認できる。exactを設定することでpathに設定した値がURLに完全に一致した場合のみ対応するコンポーネントが表示されることになる。

##ページがない404 Not Foundの設定

もしaboutなどのスペルミスがありaboubと入力した場合や意図的にルーティングの設定のないページへのアクセスが行われた場合の動作を確認する。

####1.存在しないパスへのアクセス
① 新たにApp.jsファイルにNotFoundコンポーネントを追加する。
※ NotFoundは任意の名前なので好きな名前を付ける

```App.js
function NotFound() {
  return <h2>Not Found Page</h2>;
}
```
② コンポーネントを作成したら追加したNotFoundコンポーネントをルーティングに追加する。
※ これまでは　RouteコンポーネントのpathにURLを設定していたが　Not Foundコンポーネントの場合はpathの設定は行わない

```App.js
function App() {
  return (
    <BrowserRouter>
      <h1>Hello React Router</h1>
      <Route exact path="/">
        <Home />
      </Route>
      <Route path="/about">
        <About />
      </Route>
      <Route path="/contact">
        <Contact />
      </Route>
      <Route>
        <NotFound />
      </Route>
    </BrowserRouter>
  );
}
```

####2.Not Foundコンポーネント表示
NotFoundのRouteコンポーネントを設定後、ルーティングに設定していないパスへのアクセスを行うとすべてNot Found Pageが表示されることが確認できる。しかし、/(ルート), /about, /contactにアクセスするとNot Found Pageの文字列が必ず一緒に表示される。
※Not Foundコンポーネントが必ず表示

####3.Switchコンポーネントの設定
① /aboutであればAboutコンポーネントのみ/contactであればContactコンポーネントのみ表示といったようにpathがURLに一致するコンポーネントのみ表示させる為にSwichコンポーネントを追加する。

全てのRouteコンポーネントをSwitchコンポーネントで包み、またreact-router-domからSwitchコンポーネントをimportする。

```App.js
import { BrowserRouter, Route, Switch } from 'react-router-dom';
function App() {
  return (
    <BrowserRouter>
      <h1>Hello React Router</h1>
      <Switch>
        <Route exact path="/">
          <Home />
        </Route>
        <Route path="/about">
          <About />
        </Route>
        <Route path="/contact">
          <Contact />
        </Route>
        <Route>
          <NotFound />
        </Route>
      </Switch>
    </BrowserRouter>
  );
}
```
Switchコンポーネント追加後に、/contactにアクセスするとContactコンポーネントの内容のみ表示できるようになる。

####4.Switchコンポーネント追加後の動作
Routeコンポーネントのpathに設定したURL以外にアクセスがあった場合はNot Foundコンポーネントが表示され、pathに設定されているURLにアクセスがあった場合は対応するコンポーネントの内容が表示が確認できる。

##リンクの設定
####1.リンクを追加しリンクをクリックするとページの移動ができるように設定
① リンクを追加しリンクをクリックするとページの移動ができるように設定を行なう。

```App.js
function App() {
  return (
    <BrowserRouter>
      <h1>Hello React Router</h1>
      <ul>
        <li>
          <a href="/">Home</a>
        </li>
        <li>
          <a href="/about">About</a>
        </li>
        <li>
          <a href="/contact">Contact</a>
        </li>
      </ul>
      <Switch>
        <Route exact path="/">
          <Home />
        </Route>
        <Route path="/about">
          <About />
        </Route>
        <Route path="/contact">
          <Contact />
        </Route>
        <Route>
          <NotFound />
        </Route>
      </Switch>
    </BrowserRouter>
  );
}
```

ブラウザで確認すると設定通り各ページへのリンクが表示される。リンクボタンをクリックするとクリックしたページが表示されるが表示される際にページ全体がリロードされる。
表示される内容が少ないこともありリロードがあっという間に終わるのでリロードが行われているかどうか少しわかりにくい場合もあるが、次に行う設定と比較することで動作の違いが実感できる。



##参考サイト
[React入門 #06：ルーティング処理で他のページ移動しよう]
(https://www.youtube.com/watch?v=TCpFOcqPrww)
[React入門 ～React Router編～]
(https://zenn.dev/h_yoshikawa0724/articles/2020-09-22-react-router)
[入門者でもわかるReact Routerを利用したルーティング設定の基礎]
(https://reffect.co.jp/react/react-router)