React でルーティングをする react-router を試しました。
インストール
Browserify + Babel でコンパイルするのでそのツールを React 、 react-router と一緒にインストールしておきます。
$ npm install -g browserify
$ npm install -D babelify babel-preset-es2015 babel-preset-react
$ npm install -S react react-dom react-router
Hello, World!
とりあえず画面になにか表示するところからやってみます。
import React, { Component } from 'react';
import { render } from 'react-dom';
import { Router, Route, hashHistory } from 'react-router';
class App extends Component {
render() {
return (
<div>
Hello, react-router!
</div>
);
}
}
render((
<Router history={hashHistory}>
<Route path="/" component={App} />
</Router>
), document.querySelector('#app'));
Router
コンポーネントと Route
コンポーネントを使います。 history
に hashHistory
を入れると URLの #
以降を使ってルーティングをします。 browserHistory
を使うと URL 全体を使うみたいです。
Route
に URL のパターンと表示するコンポーネントを指定します。この場合ページを開くと App
コンポーネントが作られます。
browserify
でさくっと JavaScript をまとめます。
$ browserify -o bundle.js -t [ babelify --presets es2015 --presets react ] a.js
できた bundle.js
を表示する HTML が以下です。
<!DOCTYPE html>
<meta charset="utf-8">
<div id="app"></div>
<script src="bundle.js"></script>
これを開くと App
コンポーネントによって Hello, react-router!
と表示されます。
ルーティング
これだけだと普通に表示するのと変わらないので幾つかページを作ってみます。
import React, { Component } from 'react';
import { render } from 'react-dom';
import { IndexRoute, Link, Router, Route, hashHistory } from 'react-router';
class App extends Component {
render() {
return (
<div>
<ul>
<li><Link to="/">index</Link></li>
<li><Link to="/a">page A</Link></li>
<li><Link to="/b">page B</Link></li>
</ul>
<div>
{ this.props.children }
</div>
</div>
);
}
}
class Index extends Component {
render() {
return <div>Index</div>;
}
}
class PageA extends Component {
render() {
return <div>A</div>;
}
}
class PageB extends Component {
render() {
return <div>B</div>;
}
}
render((
<Router history={hashHistory}>
<Route path="/" component={App}>
<IndexRoute component={Index} />
<Route path="/a" component={PageA} />
<Route path="/b" component={PageB} />
</Route>
</Router>
), document.querySelector('#app'));
Link
コンポーネントは URL へのリンクを作ってくれます。 hashHistory
を使っている場合は自動で #
をつけてくれるみたいです。
Route
の子要素として IndexRoute
と Route
を作ると下のパスでマッチしたうえでコンポーネントを子要素として作ってくれます。例えばこのコードだと #/
を開いた時は <App><Index /></App>
を、 #/a
を開いた時は <App><PageA /></App>
を、 #/b
を開いた時は <App><PageB /></App>
を表示します。
表示すると最初は Index
と表示されている部分が、リンクをクリックすると A
B
と内容が変化するはずです。
パラメータ
/users/123
のように URL のなかにパラメータがあるパターンも試してみます。
import React, { Component } from 'react';
import { render } from 'react-dom';
import { IndexRoute, Link, Router, Route, hashHistory } from 'react-router';
class App extends Component {
render() {
return (
<div>
<ul>
<li><Link to="/">index</Link></li>
<li><Link to="/a">page A</Link></li>
<li><Link to="/b">page B</Link></li>
</ul>
<div>
{ this.props.children }
</div>
</div>
);
}
}
class Index extends Component {
render() {
return <div>Index</div>;
}
}
class Page extends Component {
render() {
return <div>{ this.props.params.id }</div>;
}
}
render((
<Router history={hashHistory}>
<Route path="/" component={App}>
<IndexRoute component={Index} />
<Route path="/:id" component={Page} />
</Route>
</Router>
), document.querySelector('#app'));
path="/:id"
の用に指定すると this.props.params.id
にマッチした結果が入ります。 #/a
を開くと a
が、 #/b
を開くと b
が表示されます。