React Router -v4
このチュートリアルでは、以下の記事を参考に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-domThe Router
browser baseのプロジェクトでは、2つのコンポーネントを使い分ける必要がります。
- <BrowserRouter>
dynamic requests に対応する - <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と一致したurlpath— routeがもつpath 名isExact—path === pathname2つが完全に同じ名前のときtrueparams—path-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が一致した最初の子要素となります。
/— the homepage/roster— the team’s roster/roster/:number— a profile for a player, using the player’s number/schedule— the team’s schedule of games
ここで、例えば、2の /roster のpathが一致しなかった場合、下の3.4のroutingは行われません。
<Route>はどのようにrenderしているのか
Routesは3つのpropsを使って、何をrenderingするかを判断しています。
component— pathの一致が確認された後に、表示されるReactコンポーネント。routeはこのコンポーネントから得たelememtを使って、新しいelementを返す。ここでは、propsに新しい値は渡せない。render— inlineのコードをrenderingする時や、propsに新しい値を渡したいときなどに使われる。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>また、Linkに渡すpathnameは絶対パスを書く必要があります。
参考リンク
- React Router documentation
historyやmatch等、各オブジェクトの説明がわかりやすいです。
/roster— the team’s roster/roster/:number— a profile for a player, using the player’s number/schedule— the team’s schedule of games
