react-router でルーティングを試してみたけど、 実際のアプリは React + Redux で開発する予定。 その際、react-router のみではなく redux-router も一緒に使う。
redux-router は react-router の Redux バインディング。 ルーターの状態を Redux のストアで管理できるようになる。
redux-router は npm でインストール。 redux-router が依存している history も併せてインストールしておく。
npm install --save history redux-router
react-router のサンプルを Redux と redux-router を使って書き変えてみた。
var React = require("react"); var ReactDOM = require("react-dom"); var Link = require("react-router").Link; var Route = require("react-router").Route; var IndexRoute = require("react-router").IndexRoute; var combineReducers = require("redux").combineReducers; var createStore = require("redux").createStore; var compose = require("redux").compose; var Provider = require("react-redux").Provider; var connect = require("react-redux").connect; var reduxReactRouter = require("redux-router").reduxReactRouter; var routerStateReducer = require("redux-router").routerStateReducer; var createElement = require("redux-router").createElement; var ReduxRouter = require("redux-router").ReduxRouter; // HTML だけで完結したいので hash history を使う var createHashHistory = require("history").createHashHistory; // ユーザー一覧のユーザーを表示するコンポーネント var User = React.createClass({ render: function() { return ( <tr> <td> <Link to={"/users/" + this.props.user.id} query={{name: this.props.user.name}}> {this.props.user.name} </Link> </td> </tr> ); } }); // ユーザー一覧を表示するコンポーネント var Users = React.createClass({ getUsers: function() { return this.props.users.map(function(u) { return <User user={u} />; }); }, render: function() { return ( <div className="users"> <h1>ユーザー一覧</h1> <table> <thead> <tr> <th>名前</th> </tr> </thead> <tbody> {this.getUsers()} </tbody> </table> </div> ); } }); // ユーザー詳細を表示するコンポーネント var UserDetail = React.createClass({ render: function() { // パスに埋め込まれたパラメータは params から取得できる var userId = this.props.params.id; // ユーザーを取得 var user = this.props.users[userId - 1]; // 名前はクエリパラメータで受け取ったものを表示してみる return ( <div className="user-detail"> <h1>ユーザー詳細</h1> <dl> <dt>ID</dt> <dd>{user.id}</dd> <dt>名前</dt> <dd>{this.props.location.query.name}</dd> <dt>年齢</dt> <dd>{user.age}</dd> </dl> </div> ); } }); var About = React.createClass({ render: function() { return ( <div className="about"> <h1>このサンプルについて</h1> <p>react-router のサンプルです。</p> </div> ); } }); // コンテナコンポーネント var _MyApp = React.createClass({ render: function() { return ( <div> <ul> <li><Link to="/users">ユーザー一覧</Link></li> <li><Link to="/about">このサンプルについて</Link></li> </ul> <div> {this.props.children && React.cloneElement(this.props.children, { users: this.props.users })} </div> </div> ); } }); // connect でラップして、 // ストアから取り出したユーザー一覧を MyApp の props に渡せるようにする var MyApp = connect(function(state) { return { users: state.users }; })(_MyApp); // ユーザー一覧を操作する Reducer // といってもユーザー一覧の初期データを返すだけ function usersReducer(state, action) { return state || [ { id: 1, name: "香川", age: 26 }, { id: 2, name: "本田", age: 29 }, { id: 3, name: "長友", age: 29 }, { id: 4, name: "岡崎", age: 29 }, { id: 5, name: "内田", age: 28 }, { id: 6, name: "清武", age: 25 } ]; } // ストアに渡す Reducer を作成 var reducer = combineReducers({ router: routerStateReducer, users: usersReducer }); // 唯一のストアを作成 // 履歴を扱えるように reduxReactRouter ミドルウェアを適用 var store = compose( reduxReactRouter({ "createHistory": createHashHistory }) )(createStore)(reducer); // ReduxRouter を使ってルーティングを定義 ReactDOM.render(( <Provider store={store}> <ReduxRouter> <Route path="/" component={MyApp}> <IndexRoute component={Users} /> <Route path="users" component={Users} /> <Route path="users/:id" component={UserDetail} /> <Route path="about" component={About}/> </Route> </ReduxRouter> </Provider> ), document.getElementById("content") );
前回、遷移先のコンポーネントに props を渡す方法を習得したので、 状態を Redux のストアに一元管理できて良い感じ。