react-router-dom

## react-router-dom
Reactで、react-router-domを使ったルーティングを行っていきます。


## react-router-domのインストール


```:terminal
npm i -S react-router-dom
```


## ルーティング


### BrowserRouter, Route, Switchのインポート
ルーターになるコンポーネントを作るファイル内でBrowserRouter、Route、Switchをインポートします。

```:js
import { BrowserRouter, Route, Switch } from "react-router-dom";
```


|要素|内容|
|---|---|
|BrowserRouter要素|Switch要素をラップする|
|Switch要素|Route要素をラップする(ラップしたRoute要素のpathが上から1つずつ評価されていく)|
|Route要素|パスネームとページを紐付けする指定を行う|



|Route要素のプロパティ|内容|
|---|---|
|exact|pathに指定したパス文字列と、location.pathNameが完全一致した場合のみコンポーネントを返す(exact未指定の場合はfalse)|
|path|パス文字列|
|component|ページに相当するコンポーネントを指定|
|:key|useParams、useRouteMatchで使用|


#### 404ページを作る場合のRoute要素
優先順位を一番低くするため、Swith要素内の一番下にpathを書かないで配置します。
(path未指定だと全てのパスネームにマッチしてしまうため)


### ルーティングのサンプル
URLによって、ページA～C、404ページを出し分けます。

ルーター

```:src:App.js
import { BrowserRouter, Route, Switch} from "react-router-dom";
 
//各ページに相当するコンポーネントをインポート
import PageA from './page/PageA';
import PageB from './page/PageB';
import PageC from './page/PageC';
import PageD from './page/PageD';
import Page404 from './page/Page404';


function App() {

  return (

    <BrowserRouter>

      <Switch>

        <Route exact path="/" component={PageA} />
        <Route exact path="/pageb" component={PageB} />
        <Route exact path="/pagec" component={PageC} />
        <Route exact path="/paged" component={PageD} />
        <Route component={Page404} />

      </Switch>

    </BrowserRouter>

  );

}

export default App;
```

ページA

```:src/page/PageA.js
import React from 'react'

const PageA = () => {

  return (

      <p>ページAにいます。</p>

  )
}

export default PageA
```

ページB

```:src\page\PageB.js
import React from 'react'

const PageB = () => {
 
  return (
 
    <p>ページBにいます。</p>
 
  )
}
 
export default PageB
``` 

ページC

```:src\page\PageC.js
import React from 'react'

const PageC = () => {

  return (
 
    <p>ページCにいます。</p>
 
  )
}
 
export default PageC
``` 


ページD

```:src\page\PageC.js
import React from 'react'

const PageD = () => {
 
  return (
 
    <p>ページDにいます。</p>
 
  )
}
 
export default PageD
``` 


404ページ

```:src\page\Page404.js
import React from 'react'
 
const PageA = () => {
 
  return (
 
    <p>ページが見つかりません</p>
 
  )
}
 
export default PageA
``` 





### 表示確認
ブラウザのURLを変更して表示が切り替わるか確認します。


|URL|表示内容|
|---|---|
|http://localhost:3000|ページAが表示される|
|http://localhost:3000/pageb|ページBが表示される|
|http://localhost:3000/pagec|ページCが表示される|
|http://localhost:3000/paged|ページDが表示される|
|http://localhost:3000/適当な文字列|404ページが表示される|

※ホスト名は環境によって変更してください





## ページ間のリンク

### Linkタグでの遷移


#### Linkのインポート
発リンクするコンポーネントのファイルでLinkをインポートします。

```:jsx
import { Link } from "react-router-dom";
```


#### Linkコンポーネントのtoに指定できる形式

- 文字列形式　
- オブジェクト形式


##### 文字列形式

```:jsx
<Link to="/pageb">リンクテキスト</Link>
 
//パラメータを渡す事もできます。
<Link to="/pageb?sort=name">リンクテキスト</Link>
```

##### オブジェクト形式


|Link要素に指定できるオブジェクトのプロパティ|内容|
|---|---|
|pathname|パスネーム|
|search|パラメータ|
|hash|ハッシュ|
|state|ユーザ定義のデータ|



```:jsx
<Link
  to={{
    pathname: "/pageb",
    search: "?sort=name",
    hash: "hash",
    state: { key: "value" }
  }}
/>
``` 


### aタグでの遷移
Linkタグは、コンパイル後aタグになるのでaタグで書く事もできます。

#### 内部リンク

```:jsx
//下記のコードはHTMLに変換するとaタグになるので、直接aタグで記述することもできる
<Link to="/pageB" >ページBへ</Link>

//↓と同じ結果になる

<a href="/pabeB">ページBへ</a>
```

#### 外部サイトへのリンク
外部リンクはaタグで書きます。

```:js
<a href="https://qiita.com/" >Qiitaへ</a>
```

### リンクのサンプル

```:src\page\PageA.js
import React from 'react'
 
//Linkをインポート
import { Link } from "react-router-dom";

const PageA = () => {

  return (
 
    <>
      <p>ページAにいます。</p>
      <p><Link to="/pageb">ページBへ</Link></p>
      <p><a href="https://qiita.com/" target="_blank" rel="noreferrer">Qiitaへ</a></p>
    </>
 
  )
}
 
export default PageA
``` 











## react-router-domのフック


- useHistory
- useLocation
- useParams
- useRouteMatch




### useHistory
historyオブジェクトを返します。

|historyオブジェクト||
|---|---|
|history.push|URL変更|
|history.goBack	|履歴を戻る|
|history.location|historyオブジェクトのプロパティからlocationオブジェクトを取得できる|

 	
 
　	



### useLocation
locationオブジェクトを返します。

|locationオブジェクト|内容|
|---|---|
|location.pathname|現在のパス名|
|location.search|現在のパラメータ|
|location.hash|現在のハッシュ値|
|location.state	|ユーザ定義のデータ|

 	
 	
 	
 



#### historyとlocationの違い


|URL変更時の挙動|内容|
|---|---|
|history|常に同じオブジェクト|
|location|新しいオブジェクトが作られる|


|useLocation/useHistory|使い分け|
|---|---|
|useLocation|レンダリング中にlocationが必要なときに使う|
|useHistory|レンダリング中にlocationが必要ないときに使う|


 
 	













#### hitstory.pushでの遷移のサンプル
onClickなどのhandleではLinkタグ、aタグが使えないので、history.pushで遷移させます。
history.pushもLinkタグと同じく文字列とオブジェクトでの遷移先の指定ができます。

ルーター

```:src\App.js
//追加でuseHistoryをimport
import { BrowserRouter, Route, Switch,useHistory} from "react-router-dom";

//各ページに相当するコンポーネントをインポート
import PageA from './page/PageA';
import PageB from './page/PageB';
import PageC from './page/PageC';
import Page404 from './page/Page404';

function App() {

  //historyの取得
  const history = useHistory();

  return (

    { /* BrouserRouterにhistoryを追加 */ },
    <BrowserRouter history={history}>

      <Switch>

        <Route exact path="/" component={PageA} />
        <Route exact path="/pageb" component={PageB} />
        <Route exact path="/pagec" component={PageC} />
        <Route exact path="/paged" component={PageC} />
        <Route component={Page404} />

      </Switch>

    </BrowserRouter>

  );

}

export default App;
``` 
 

発リンクするコンポーネント側


```:src
import React from 'react'

//追加でuseHistoryをインポート
import { Link,useHistory } from "react-router-dom";

const PageA = () => {

  //historyの取得
  const history = useHistory();

  return (

    <>
      <p>ページAにいます。</p>
      <p><Link to="/pageb">ページBへ</Link></p>

      <p
         onClick={() => {
           history.push("/pagec");
         }}
       >
         ページCへ
       </p>

      <p><a href="https://qiita.com/" target="_blank" rel="noreferrer">Qiitaへ</a></p>
    </>

  )
}
 
export default PageA
``` 




#### locationを指定した情報の表示のサンプル



ページA
Link要素で、オブジェクト形式で情報を付加して、ページDにリンクします。

```:src\page\PageA.js
import React from 'react'

//追加でuseHistoryをインポート
import { Link,useHistory } from "react-router-dom";

const PageA = () => {

  //historyの取得
  const history = useHistory();

  return (

    <>
      <p>ページAにいます。</p>
      <p><Link to="/pageb">ページBへ</Link></p>

      <p
         onClick={() => {
           history.push("/pagec");
         }}
       >
         ページCへ
       </p>

       <p
         onClick={() => {
           history.push({
             pathname:"/paged",
             search: "?sort=aaa",
             hash: "#hash",
             state: { test: "成功" }
            });
         }}
       >
         ページDへ
       </p>

      <p><a href="https://qiita.com/" target="_blank" rel="noreferrer">Qiitaへ</a></p>
    </>

  )
}

export default PageA
``` 

ページD
渡した情報が表示されます。

```:src/page/PageD.js
import React from 'react'

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

const PageD = () => {

  const location = useLocation();

  return (

    <>
      <p>ページDにいます。</p>

      {/* locationで情報を表示します。 */}
      <p>pathname: {location.pathname}</p>
      <p>search: {location.search}</p>
      <p>hash: {location.hash}</p>
      <p>state.test: {location.state.test}</p>

    </>

  )

}

export default PageD
```


### useParams
URLのパスの中で動的に変化する部分の値を取得できます。



#### パラメータによって表示を変更するサンプル

ルーター
ページEへのリンクを追加(パラメータを付与できるようにする)

```:src\App.js
import { BrowserRouter, Route, Switch,useHistory} from "react-router-dom";

import PageA from './page/PageA';
import PageB from './page/PageB';
import PageC from './page/PageC';
import PageD from './page/PageD';
import PageE from './page/PageE';
import Page404 from './page/Page404';

function App() {

  const history = useHistory();

  return (

    <BrowserRouter history={history}>

      <Switch>

        <Route exact path="/" component={PageA} />
        <Route exact path="/pageb" component={PageB} />
        <Route exact path="/pagec" component={PageC} />
        <Route exact path="/paged" component={PageD} />

        {/* ページEへのリンクを追加(idというパラメータをつける) */}
        <Route exact path="/pagee/:id" component={PageE} />
        <Route component={Page404} />

      </Switch>

    </BrowserRouter>

  );

}

export default App;
``` 



ページA
ページEへのリンク追加

```:src\page\PageA.js
import React from 'react'

import { Link,useHistory } from "react-router-dom";

const PageA = () => {

  const history = useHistory();

  return (

    <>
      <p>ページAにいます。</p>
      <p><Link to="/pageb">ページBへ</Link></p>

      <p
         onClick={() => {
           history.push("/pagec");
         }}
       >
         ページCへ
       </p>

       <p
         onClick={() => {
           history.push({
             pathname:"/paged",
             search: "?sort=aaa",
             hash: "#hash",
             state: { test: "成功" }
            });
         }}
       >
         ページDへ
       </p>

      {/* ページEにリンク(パラメータ違いで3つ)*/}
      <p><Link to="/pagee/yamada">ページEへ(yamada)</Link></p>
      <p><Link to="/pagee/sato">ページEへ(sato)</Link></p>
      <p><Link to="/pagee">ページEへ(パラメータなし)</Link></p>

      <p><a href="https://qiita.com/" target="_blank" rel="noreferrer">Qiitaへ</a></p>
    </>

  )
}
 
export default PageA
``` 

ページE
新規作成

```:src\page\PageE.js
import React from 'react'

//useParamをインポート
import { useParams } from "react-router-dom";

const PageE = () => {

  //パラメータを取得
  const {id} = useParams();

  return (

    <>
      <p>ページEにいます。</p>

      {/* 受け取ったパラメータを表示 */}
      <p>ID：{id}</p>
    </>

  )
}

export default PageE
``` 







### useRouteMatch
パラメータによってコンポーネント単位でレンダリングの制御ができます。

#### パラメータによってコンポーネントを出し分けるサンプル

ページEを変更します。

```:src\page\PageE.js
import React from 'react'

//useRouteMatchをインポート
import { useRouteMatch  } from "react-router-dom";

const PageE = () => {

  //条件の指定
  const matchYamada = useRouteMatch('/pagee/yamada');


  return (

    <>
      <p>ページEにいます。</p>

      {/* パラメータがyamadaのとき表示するコンポーネント */}
      {matchYamada ? <p>IDがyamadaなので表示されています</p> : null}

    </>

  )
}
 
export default PageE
```