react-routerで簡単なSingle-page applicationを作ってみる
「Webpack+BabelでReactを使ってみる」では、WebpackとBabelを用いてReactアプリケーションを書いた。 ここでは、react-routerモジュールを使い、簡単なルーティングを含むSingle-page application(SPA)を書いてみる。
環境
Ubuntu 14.04.4 LTS 64bit版
$ uname -a Linux vm-ubuntu64 3.19.0-25-generic #26~14.04.1-Ubuntu SMP Fri Jul 24 21:16:20 UTC 2015 x86_64 x86_64 x86_64 GNU/Linux $ lsb_release -a No LSB modules are available. Distributor ID: Ubuntu Description: Ubuntu 14.04.4 LTS Release: 14.04 Codename: trusty $ nodejs --version v4.4.2 $ npm --version 2.15.0
ディレクトリの作成
「Webpack+BabelでReactを使ってみる」と同様に、スクリプトを置くディレクトリを作成し必要なモジュールをインストールした後、コンフィグファイルを準備する。 ここでは、追加でreact-routerをインストールする。
$ mkdir helloreact2 $ cd helloreact2/ $ npm init -y $ npm install --save-dev webpack babel-loader babel-core babel-preset-react babel-preset-es2015 $ npm install --save react react-dom $ npm install --save react-router
package.jsonを編集し、npmからWebpackを実行できるようにする。
{
"name": "helloreact2",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"build": "rm -rf scripts/*.js && webpack",
"watch": "rm -rf scripts/*.js && webpack -w"
},
"keywords": [],
"author": "",
"license": "ISC",
"devDependencies": {
"babel-core": "^6.7.6",
"babel-loader": "^6.2.4",
"babel-preset-es2015": "^6.6.0",
"babel-preset-react": "^6.5.0",
"webpack": "^1.12.15"
},
"dependencies": {
"react": "^15.0.1",
"react-dom": "^15.0.1",
"react-router": "^2.2.2"
}
}
次に、webpack.config.jsを作成し、Babelで./src/app.jsを./scripts/bundle.jsにコンパイルするよう指定する。
module.exports = {
entry: "./src/app.js",
output: {
path: __dirname + "/scripts",
filename: "bundle.js"
},
module: {
loaders: [
{
test: /\.js$/,
exclude: /node_modules/,
loader: "babel-loader",
query: {
presets: ["react", "es2015"]
}
}
]
}
};
最後に、ソースファイルとコンパイル後のスクリプトを置くディレクトリを作成する。
$ mkdir src scripts
ルーティングするスクリプトを書いてみる
まず、コンパイルされたJavaScriptを読み込んで実行するHTMLファイルを作成する。
<!-- index.html -->
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8"/>
<title>Hello, React!</title>
</head>
<body>
<div id="content"></div>
<script type="text/javascript" src="scripts/bundle.js"></script>
</body>
</html>
次に、Reactとreact-routerを使い、簡単なルーティングに合わせてページ内容を出力するスクリプトを書く。
// src/app.js
import React from 'react'
import ReactDOM from "react-dom";
import { Router, Route, Link, hashHistory } from 'react-router'
const users = [
{name: "alice"}, {name: "bob"}, {name: "charlie"}
];
const App = React.createClass({
render() {
return (
<div>
<ul>
<li><Link to="/">Home</Link></li>
<li><Link to="/user">Users</Link></li>
</ul>
<h1>Hello, React!</h1>
<p>This is an example site using <em>react-router</em>.</p>
{this.props.children}
</div>
)
}
})
const Users = React.createClass({
render() {
return (
<div>
<h2>Users</h2>
<ul>
{users.map(user => (
<li key={user.name}><Link to={`/user/${user.name}`}>{user.name}</Link></li>
))}
</ul>
</div>
)
}
})
const User = React.createClass({
render() {
return (
<div>
<h2>User: {this.props.params.userName}</h2>
<p>Welcome to {this.props.params.userName}'s page!</p>
</div>
)
}
})
const NoMatch = React.createClass({
render() {
return (
<div>
<h2>Oops... something is wrong</h2>
</div>
)
}
})
ReactDOM.render(
<Router history={hashHistory}>
<Route path="/" component={App}>
<Route path="/user" component={Users}/>
<Route path="/user/:userName" component={User}/>
<Route path="*" component={NoMatch}/>
</Route>
</Router>,
document.getElementById("content")
);
上のコードは、/userにアクセスしたときハードコードされた各ユーザのページへのリンクを含むページ、/user/:userNameにアクセスしたとき各ユーザのページを表示する。
ここでは、簡略化のためハードコードされていないユーザ名についてもページ内容が表示されるようになっている。
また、<Link to="foo"></Link>におけるfooは、<Route path="foo"/>のfooと対応している。
コンパイルして表示してみる
npm経由でWebpackを実行し、上のスクリプトをJavaScriptコードにコンパイルしてみる。
$ npm run build
> helloreact2@1.0.0 build /home/user/tmp/helloreact2
> rm -rf scripts/*.js && webpack
Hash: e10002df15950c272793
Version: webpack 1.12.15
Time: 5099ms
Asset Size Chunks Chunk Names
bundle.js 851 kB 0 [emitted] main
+ 223 hidden modules
Python等を用いてWebサーバを起動した後、ブラウザでindex.htmlにアクセスした際のスクリーンショットを示すと次のようになる。
$ python -m SimpleHTTPServer Serving HTTP on 0.0.0.0 port 8000 ...

適当にリンクをクリックすると、JavaScriptによるページの書き換えが行われ、対応するページ内容が表示されることが確認できる。
また、履歴を戻ると前のページ内容に更新されることが確認できる。
なお、URLに?_k=44vmmnのようなパラメータがついているが、これはPOSTされたデータなどを保存するために使われている(参考)。