Edited at

react-router-dom v4 入門してみた

SPAでは、DOMをごりごり書き換えて、ユーザに複数のページがあるように見せたとしても、Urlを書き換えない限り、ブラウザは単一のページでしか認識しません。そこで、ヒストリーAPIを操作して、履歴やブックマークから、任意のページに飛んでこれるようにします。

Reactの場合は、ヒストリーAPIを操作しつつ、画面遷移もしてくれる、react-router-domというライブラリがあるので、基本はそれを使う形になります。

あと自分はqiitaに本格的な記事を書いたのは初めてなので、間違っている部分があったら教えてくれると嬉しいです!!


プロジェクトの作成

特にwebpack.config.js等で特殊なことをする訳ではないので、環境構築は Create React Appに丸投げします。

    $ create-react-app transition-animation

$ cd transition-animation

とりあえずテスト用の環境が作成されます


必要なモジュールのインストール

ルーティング兼ヒストリーAPI操作用の react-router-dom を使用するのでインストール

    $ yarn add react-transition-group react-router-dom

元々あったApp.jsの中のコンテンツは不要なので消しておきましょう


App.js

import React, { Component } from 'react';

import './App.css';

class App extends Component {
render() {
return (
<div className="App">
{/*この中にあったものを削除*/}
</div>
);
}
}

export default App;



メニュー画面の作成

App.jsがあった場所と同じディレクトリに、Menu.jsを作成します。一先ず何の動きもないメニュー画面の雛形だけ作成します。


Menu.js

import React from "react";

const Menu = () => {
const liStyle = {
display: 'inline',
width: '100px'
}

return (
<div style={{width: '500px', textAlign: 'left'}}>
<ul style={{display: 'flex'}}>
<li style={liStyle}>top</li>
<li style={liStyle}>page1</li>
<li style={liStyle}>page2</li>
<li style={liStyle}>page3</li>
</ul>
</div>)
}

export default Menu


作成したメニュー画面を、さっきのApp.jsで読み込みます


App.js

import React, { Component } from 'react';

import './App.css';
import Menu from "./Menu"; // <= 作成したメニュー画面を読み込み

class App extends Component {
render() {
return (
<div className="App">
<Menu/> //<= さっきコンテンツを削除した場所にメニュー画面を配置
</div>
);
}
}

export default App;


サーバーを起動すると、以下のような画面が表示されます

    $ npm run start

ひながた

ここから、react-router-domを使用して、 『top page1 page2 page3 』 をクリックした時に、画面遷移が発生するようにしていきます。


react-router-domでルーティングさせる

react-router-domから必要なモジュールをインポートします。


Menu.js

   import {BrowserRouter as Router, Link, Route} from "react-router-dom";



  • BrowserRouterが、画面遷移時にヒストリーAPIに履歴情報を追加してくれるコンポーネントになります。 Routerとエイリアスを定義されることが多いです。BrowserRouterの子要素にRouteLinkを入れて使用します。

  • Link いわゆるaタグです。(というか実際aタグに変換される)クリックすると、to要素に指定したlocaltion.pathnameへUrlを変更します。

  • Route localtion.pathnameが、path要素に指定したものとマッチしていた場合、componentに渡されたReactコンポーネントを描写します。

  • 基本的な使い方は、LinkのtoとRouteのpathを合わせて、それをBrowseRouterの中に入れて使う感じです。

まずは全体をBrowseRouterでラップ


Menu.js

    return (

<Router>
<div style={{width: '500px', textAlign: 'left'}}>
<ul style={{display: 'flex'}}>
<li style={liStyle}>top</li>
<li style={liStyle}>page1</li>
<li style={liStyle}>page2</li>
<li style={liStyle}>page3</li>
</ul>
</div>
</Router>)
}

次に ページの中身用のコンポーネントを作成し、Routecomponentに渡してやります。


Menu.js

import React from "react";

import {BrowserRouter as Router, Link, Route} from "react-router-dom";

//ページの中身用のコンポーネントを作成
const topPage = () => <div><h1>Top Page</h1>ここがトップページです</div>
const page1 = () => <div><h1>page1</h1>1枚目のページです</div>
const page2 = () => <div><h1>page2</h1>2枚目のページです</div>
const page3 = () => <div><h1>page3</h1>3枚目のページです</div>

const Menu = () => {
const liStyle = {
display: 'inline',
width: '100px'
}

return (
<Router>
<div style={{width: '500px', textAlign: 'left'}}>
<ul style={{display: 'flex'}}>
<li style={liStyle}>top</li>
<li style={liStyle}>page1</li>
<li style={liStyle}>page2</li>
<li style={liStyle}>page3</li>
</ul>

//Routeaを配置 exactを指定してマッチングを厳密に
<div style={{marginLeft: '50px'}}>
<Route path='/' exact component={topPage}/>
<Route path='/page1' exact component={page1}/>
<Route path='/page2' exact component={page2}/>
<Route path='/page3' exact component={page3}/>
</div>
</div>
</Router>)
}

export default Menu


最後に『top page1 page2 page3』のテキストをLinkでラップしたものを配置して画面遷移を行う仕組みができました。


Menu.js

import React from "react";

import {BrowserRouter as Router, Link, Route} from "react-router-dom";

const topPage = () => <div><h1>Top Page</h1>ここがトップページです</div>
const page1 = () => <div><h1>page1</h1>1枚目のページです</div>
const page2 = () => <div><h1>page2</h1>2枚目のページです</div>
const page3 = () => <div><h1>page3</h1>3枚目のページです</div>

const Menu = () => {
const liStyle = {
display: 'inline',
width: '100px'
}

return (
<Router>
<div style={{width: '500px', textAlign: 'left'}}>
<ul style={{display: 'flex'}}>
<li style={liStyle}><Link to='/'>top</Link></li>
<li style={liStyle}><Link to='/page1'>page1</Link></li>
<li style={liStyle}><Link to='/page2'>page2</Link></li>
<li style={liStyle}><Link to='/page3'>page3</Link></li>
</ul>

<div style={{marginLeft: '50px'}}>
<Route path='/' exact component={topPage}/>
<Route path='/page1' exact component={page1}/>
<Route path='/page2' exact component={page2}/>
<Route path='/page3' exact component={page3}/>
</div>
</div>
</Router>)
}

export default Menu


リンク

クリックすると画面が切り替わると同時に、ブラウザのurlも変わっているはずです。


Switchでどのurlにもヒットしない場合のページを表示

react-router-domにはSwitchというコンポーネントが存在します。このコンポーネントの動作は、一般的なプログラミング言語のSwitch文と似たようなもので、上から順にpathにマッチするRouteを探して見つかればそれだけを描写します。Route達ををswitchでラップ + 末尾にpathの指定がないRouteを配置することで、どのurlにもヒットしない場合、任意のページを表示させることができます。


Menu.js

import React from "react";

import {BrowserRouter as Router, Link, Route, Switch} from "react-router-dom";

const topPage = () => <div><h1>Top Page</h1>ここがトップページです</div>
const page1 = () => <div><h1>page1</h1>1枚目のページです</div>
const page2 = () => <div><h1>page2</h1>2枚目のページです</div>
const page3 = () => <div><h1>page3</h1>3枚目のページです</div>
const page404 = () => <div><h1>404</h1>存在しないページです</div> //<= ヒットしなかった時用のページを追加

const Menu = () => {
const liStyle = {
display: 'inline',
width: '100px'
}

return (
<Router>
<div style={{width: '500px', textAlign: 'left'}}>
<ul style={{display: 'flex'}}>
<li style={liStyle}><Link to='/'>top</Link></li>
<li style={liStyle}><Link to='/page1'>page1</Link></li>
<li style={liStyle}><Link to='/page2'>page2</Link></li>
<li style={liStyle}><Link to='/page3'>page3</Link></li>
</ul>

<div style={{marginLeft: '50px'}}>
<Switch>
<Route path='/' exact component={topPage}/>
<Route path='/page1' exact component={page1}/>
<Route path='/page2' exact component={page2}/>
<Route path='/page3' exact component={page3}/>
<Route exact component={page404}/> //<= 一番末尾に追加 pathの指定も、対応するLinkの追加も必要ない
</Switch>
</div>
</div>
</Router>)
}

export default Menu


もちろん、


Menu.js

<Switch>

<Route path='/' exact component={topPage}/>
<Route path='/page1' exact component={page1}/>
<Route path='/page2' exact component={page2}/>
<Route path='/page3' exact component={page3}/>
<Route exact component={topPage}/>
</Switch>

のようにすれば、topPageに戻らせることも可能です。

次回は画面遷移時にアニメーションを挿入する方法を解説します。