数か月前にreact-routerとReduxを同時に学ぼうとして挫折したので、今回はまず順を追ってreact-routerを学習する。
インストールするもの
vueのときと同じかな? と最初に何も考えずにreact-routerを入れたのですが、調べるとどうやらこれはコアの部分。
ウェブアプリケーションを構築する為に必要なのは「react-router-dom」の方でした(こちらを入れるとreact-routerも一緒に入ってくれます)。
今回は
react-router-dom 5.0.1
を使用しています。
まずはApp.jsにざらっと書いてみる
import React from 'react'
import ReactDOM from 'react-dom'
import './styles.scss'
import App from './App'
ReactDOM.render(
<App />,
document.getElementById('root')
)
import React, { Component } from 'react'
import { BrowserRouter, Route, Link } from 'react-router-dom'
const App = () => (
<BrowserRouter>
<h1>react-routerに入門する。</h1>
<nav>
<ul>
<li><Link to='/'>Index</Link></li>
<li><Link to='/second'>Second</Link></li>
<li><Link to='/third'>Third</Link></li>
</ul>
</nav>
<article>
<Route exact path='/' component={Index} />
<Route path='/second' component={Second} />
<Route path='/third' component={Third} />
</article>
</BrowserRouter>
)
const Index = () => (
<div>
<h2>Index</h2>
<p>インデックスページ</p>
</div>
)
const Second = () => (
<div>
<h2>Second</h2>
<p>二番目のページです</p>
</div>
)
const Third = () => (
<div>
<h2>Third</h2>
<p>三番目のページです</p>
</div>
)
export default App
リンクは<Link to='/'>
で書き、<Route />
でルーティングを設定すれば良いので、ここまではVueのときと然程遠くない感覚で書けました。
(色々な方の記事を見ていると、BrowserRouterにasで「Router」と付けている人が多いみたいだったんですが何故だろう……)
ページごとにファイルを分けたい
といってもこれは単に分けるだけ。
import React, { Component } from 'react'
const Index = () => (
<div>
<h2>Index</h2>
<p>二番目のページです</p>
</div>
)
export default Index
他ページも同様に。
import React, { Component } from 'react'
import { BrowserRouter, Route, Link } from 'react-router-dom'
import Index from './pages/Index'
import Second from './pages/Second'
import Third from './pages/Third'
const App = () => (
<BrowserRouter>
<h1>react-routerに入門する。</h1>
<nav>
<ul>
<li><Link to='/'>Index</Link></li>
<li><Link to='/second'>Second</Link></li>
<li><Link to='/third'>Third</Link></li>
</ul>
</nav>
<article>
<Route exact path='/' component={Index} />
<Route path='/second' component={Second} />
<Route path='/third' component={Third} />
</article>
</BrowserRouter>
)
export default App
動的ルートマッチングしたい
したい。
今回はSecondの下層ページとして実装します。
まずは中身から。
import React, { Component } from 'react'
const SecondChild = (props) => {
const { id } = props.match.params
return (
<div>
<h2>SecondChild</h2>
<p>{id}のページです</p>
</div>
)
}
export default SecondChild
次いでApp.jsを書いていくんですが……。
以下、失敗例です(´・ω・`)。
import React, { Component } from 'react'
import { BrowserRouter, Route, Link } from 'react-router-dom'
import Index from './pages/Index'
import Second from './pages/Second'
import SecondChild from './pages/SecondChild'
import Third from './pages/Third'
const App = () => (
<BrowserRouter>
<h1>react-routerに入門する。</h1>
<nav>
<ul>
<li><Link to='/'>Index</Link></li>
<li><Link to='/second'>Second</Link></li>
<li><Link to='/second/neko'>Second-neko</Link></li>
<li><Link to='/third'>Third</Link></li>
</ul>
</nav>
<article>
<Route exact path='/' component={Index} />
<Route path='/second' component={Second} />
<Route path='/second/:id' component={SecondChild} />
<Route path='/third' component={Third} />
</article>
</BrowserRouter>
)
export default App
あれっ、ふたつ出ちゃった。
SecondとSecondChildを逆に書くべきだった?と調べてみるもそういうことではなく。
単純にexactの記載が抜けていたのでした。
<article>
<Route exact path='/' component={Index} />
<Route exact path='/second' component={Second} />
<Route path='/second/:id' component={SecondChild} />
<Route path='/third' component={Third} />
</article>
Routeは前方一致するものがあれば全てのコンポーネントが表示されるため、一致させたくないものにはexactが必要です。
これで完全一致の場合のみ表示されるようになります。
余談
今回記事を書くにあたって、vue-routerで言うところの:to={name: 'hoge'}
的な書き方をしたいと思ったのですが、どうにも書き方を見付けられませんでした。
単に見付けられていないのか、そもそもreactでは必要にならないのか……。
触っていくうちに分かると思うので、今後の課題とします。
参考記事
react-router@v4を使ってみよう:シンプルなtutorial
https://qiita.com/muiscript/items/b4ca1773580317e7112e
React Roter v4 (RRv4) を使用した時の備忘録
https://blog.kazu69.net/2017/08/10/using-react-router-v4/