React Router -v4

Tuyoshi Akiyama
Jul 24, 2017 · 9 min read

このチュートリアルでは、以下の記事を参考にreact-router -version4を使っていきます。


インストール方法

react-routerは3つのパッケージから成り立っています。

  • react-router
    routingの基盤となるコンポーネントや関数をもつ
  • react-router-dom
    browser用のコンポーネントをもつ
  • react-router-native
    react-native用のコンポーネントをもつ

react-routerを直接インストールするよりは、それぞれの用途にあわせたpackageを入れるのが一般的なパターンになります。

今回は、ウェブサイト用のパッケージを入れていきます。

yarn add --save react-router-dom

The Router

browser baseのプロジェクトでは、2つのコンポーネントを使い分ける必要がります。

  1. <BrowserRouter>
    dynamic requests に対応する
  2. <HashRouter>
    静的Web siteに対応する

基本的には、1の <BrowserRouter>を使います。


history

それぞれrouterは、history objectを作って、現在の場所とre-renderingするサイトが変わる度に履歴を保持します。

history objectによって他のコンポーネントも機能するため、このオブジェクトはroterのrender()内に置かれる必要があります。

history がレンダリングされない場合、react-routerコンポーネントはrouting機能を持たなくなります。


Readering a <Router>

routerコンポーネントは、一つの子要素だけを受け取るように、作られています。これに合わせる為に、以下のように、全要素を<App>コンポーネントにまとめてrenderingされるのが、よく使われています。

import { BrowserRouter } from 'react-router-dom'// this component will be rendered by our <___Router>
const App = () => (
<div>
<Header />
<Main />
</div>
)
ReactDOM.render((
<BrowserRouter>
<App />
</BrowserRouter>
), document.getElementById('root'))

Routes

<Route>コンポーネントは、locationのpathが一致したものをレンダリングしたい時に、<Route></Route>のように使われるブロック要素です。


path

pathは<Route>に渡されるprop stringで、routingする際のpathに一致するものを指します。

現在のpathnameとpathとが一致する時、React要素のroutingが起こります。それぞれのpathが一致しない場合は、routingしません。

また、その前のコンポーネントのrouting処理が機能しない場合、コンポーネントはroutingしません。

例えば、 <Route path=’/roster’/>が現在のパスの場合

pathnameには'/roster' や'/roster/2'が一致するものとなります。


Matching paths

path-to-regexpパッケージは、route 要素内のprop.pathとcurrent pathとが一致するかを見分ける役割を果たします。

routeが一致した際、 match objectが以下のプロパティを持って作られます。

  • url — 現在のpathnameがpathと一致したurl
  • path — routeがもつpath 名
  • isExactpath === pathname 2つが完全に同じ名前のときtrue
  • paramspath-to-regexp でpathnameから取ってきた値をもつobject

Creating routes

まず、以下のコード例を見ていきます。

<Switch>
<Route exact path='/' component={Home}/>
{/* both /roster and /roster/:number begin with /roster */}
<Route path='/roster' component={Roster}/>
<Route path='/schedule' component={Schedule}/>
</Switch>

この例では、<Switch>で囲むことで、 <Route>を一つの場所にまとめてrendering処理をiteratesします。

最初に表示される(rendering)されるものは、pathが一致した最初の子要素となります。

  1. / — the homepage
  2. /roster — the team’s roster
  3. /roster/:number — a profile for a player, using the player’s number
  4. /schedule — the team’s schedule of games

ここで、例えば、2の /roster のpathが一致しなかった場合、下の3.4のroutingは行われません。


<Route>はどのようにrenderしているのか

Routesは3つのpropsを使って、何をrenderingするかを判断しています。

  1. component — pathの一致が確認された後に、表示されるReactコンポーネント。routeはこのコンポーネントから得たelememtを使って、新しいelementを返す。ここでは、propsに新しい値は渡せない。
  2. render — inlineのコードをrenderingする時や、propsに新しい値を渡したいときなどに使われる。
  3. children — 上の2つとは違い、pathの一致に関係なくrenderingが行われる。

基本は上の1,2 が使われます。3のpropsが使われるときは、以下のような場合があります。

<Route path='/page' children={(props) => (
props.match
? <Page {...props}/>
: <EmptyPage {...props}/>
)}

上の例は、pathが一致しなかった場合、errorページを表示します。


コード例

ここまで、react-routerの概要をみてきました。次に、実際に例題のコードを用いて、処理を見ていきます。

import { Switch, Route } from 'react-router-dom'const Main = () => (
<main>
<Switch>
<Route exact path='/' component={Home}/>
<Route path='/roster' component={Roster}/>
<Route path='/schedule' component={Schedule}/>
</Switch>
</main>
)

ホームページへは、exact propが渡されているので、path名とrouteが持つpathが完全に一致’/’の時にroutingします。


Nested Routes

例えば上のコード例では、’/roaster’はRoasterコンポーネントにroutingします。prop.pathが path='/roster' の時と path='/roster/:number の時と違うコンポーネントを表示したい場合、以下の様なコードになります。

const Router = () => (
<div>
<h2>this is a roaster page</h2>
<Switch>
<Route exact path='/roster' component={FullRoaster} />
<Route path ='roster/:number' component={Player} />
</Switch>
</div>
)

一度routerコンポーネントを呼んで、その中でまた、routing処理をしています。

これは同じprefixを持つpathを扱う時に、有効な手になります。


path params

props.pathnameの値に変数を入れる場合、下記コード例ではprops.match.params.numberのように参照しています。

つまり、props.match.params オブジェクトの中で変数の処理を行われていることになります。

pathのパラメーターの詳細については、path-to-regexpdocumentationこちらにまとめられています。

では、<Plaryer>コンポーネントの処理を見ています。

// an API that returns a player object
import PlayerAPI from './PlayerAPI'
const Player = (props) => {
const player = PlayerAPI.get(
parseInt(props.match.params.number, 10)
)
if (!player) {
return <div>Sorry, but the player was not found</div>
}
return (
<div>
<h1>{player.name} (#{player.number})</h1>
<h2>{player.position}</h2>
</div>
)

Links

Linkコンポーネントは、全ページ読み込みせずにページ遷移を行う機能をもちます。

Linkをクリックした時、URLがアップデートされて、re-loadなしで内容がrenderingされます。

Linkは下の次のコードのように、propsにオブジェクトを渡すこともできます。

<Link to={{ pathname: '/roster/7' }}>Player #7</Link>

また、を書く必要があります。


参考リンク

  1. /roster — the team’s roster
  2. /roster/:number — a profile for a player, using the player’s number
  3. /schedule — the team’s schedule of games

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade