history.pushでurlは変わるのに画面遷移しないときの対処法

## はじめに
React(react-router-dom)で画面遷移をさせようと思った時にブラウザの表示しているURLは変わるのに画面が遷移しなかったので、その時の対処法を書き残します。

先に原因と対処法が見たい方は[こちら](#原因と対処法)

### 環境
* Ubuntu 20.4
* Node 12.18.3
* npm 6.14.6
* npx 6.14.6

## 画面遷移させるアプリケーションを作る(現象の再現)
### Reactアプリのテンプレートから作成
まずはともかく`create-react-app`
今回はTypeScriptを使用。

```
npx create-react-app my-app --template typescript
```

### react-router-domのインストール
```
cd my-app
npm i react-router-dom
npm i --save-dev @types/react-router-dom
``` 

### 画面遷移するアプリケーションへ変更
それぞれのページにボタンを配置し、ボタンをクリックした際にhistory.push()を実行し画面に遷移させる。

```App.tsx
import React from "react";
import {
  BrowserRouter as Router,
  Switch,
  Route,
  useHistory
} from "react-router-dom";
import Home from './Home'
import Pages from './Pages'

const App: React.FC = () => {
  const history = useHistory()

  const goToHome = () => {
    history.push('/')
  }
  const goToPages = () => {
    history.push('/pages')
  }
  return (
    <Router>
      <Switch>
        <Route exact path='/'>
          <Home goToPages={goToPages}/>
        </Route>
        <Route exact path='/pages'>
          <Pages goToHome={goToHome}/>
        </Route>
      </Switch>
    </Router>
  );
}

export default App;

```

```Home.tsx
import React from 'react'

interface Prop {
  goToPages: () => void,
}
const Home: React.FC<Prop> = (props) => {
  const { goToPages } = props
  return (
    <div>
      <h1>ホームだよ</h1>
      <button onClick={goToPages}>Pagesへ</button>
    </div>
  )
}

export default Home

```

```Pages.tsx
import React from 'react'

interface Prop {
  goToHome: () => void,
}
const Pages: React.FC<Prop> = (props) => {
  const { goToHome } = props
  return (
    <div>
      <h1>ページだよ</h1>
      <button onClick={goToHome}>ホームへ</button>
    </div>
  )
}

export default Pages
```


```index.tsx
import React from 'react';
import ReactDOM from 'react-dom';
import {
  BrowserRouter as Router,
} from "react-router-dom";
import App from './App';
import reportWebVitals from './reportWebVitals';

ReactDOM.render(
  <React.StrictMode>
    <Router>
      <App />
    </Router>
  </React.StrictMode>,
  document.getElementById('root')
);

// If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
reportWebVitals();

```

* `index.tsx` 
    * App.tsxで使用している**useHistory**がRouterコンポーネント内にないと動作しないため、**とりあえず**Routerで囲う
* `App.tsx`
    * Switch,Routeによるページ遷移
* `Home.tsx` `Pages.tsx`
    * ページ遷移ボタン設置

そして`npm start`

![reactRouterNG.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/649992/b57dcefa-aacc-1c23-d4ce-b5fa072c5e38.gif)


・・・うーん？？
ボタンをクリックした際にURLは変わっているが、画面が変わらない。
リロードをするときちんとそのページが表示される。


#原因と対処法
`App.tsx`と`index.tsx`にRouterが重複して存在している。
→Routerの子コンポーネントにRouterが存在している

```App.tsx
import React from "react";
import {
  Switch,
  Route,
  useHistory
} from "react-router-dom";
import Home from './Home'
import Pages from './Pages'

function App() {
  const history = useHistory()

  const goToHome = () => {
    history.push('/')
  }
  const goToPages = () => {
    history.push('/pages')
  }
  return (
    <Switch>{/**ここ */}
      <Route exact path='/'>
        <Home goToPages={goToPages} />
      </Route>
      <Route exact path='/pages'>
        <Pages goToHome={goToHome} />
      </Route>
    </Switch>
  );
}

export default App;


```
変更して再度実行

![reactRouterOK.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/649992/facd60fe-5b29-e301-dde5-60595bbbc154.gif)


・・・いい感じ!!

## まとめ
今回は`App.tsx`にページ遷移の関数を作成し、Propsとして渡して実行するというパターンでした。
`index.tsx`ではなく`App.tsx`内にBrowserRouter(Router)を配置する際にはそれぞれのページコンポーネント(Home,Pages)にuseHistoryを記述するといいと思います。

**アプリケーションにはBrowserRouter(Router)は一つと覚えておくといいと思います。**

今後も精進していきます。