かずきのBlog@hatena

日本マイクロソフトに勤めています。XAML + C#の組み合わせをメインに、たまにASP.NETやJavaなどの.NET系以外のことも書いています。掲載内容は個人の見解であり、所属する企業を代表するものではありません。

React + TypeScriptでreact-router-redux

react-routerをreduxで使うためのreact-router-reduxというものがあります。

先日、これの型定義ファイルが公開されてたので使ってみました。

react-router-reduxの公式サイトはこちらになります。

github.com

素のreactのプロジェクトに対して…

  • react-redux
  • react-router
  • react-router-redux
  • redux
  • history

あたりを追加してやれば使える感じになります(多いよね…)

reducerの設定

react-router-reduxを使うには、routingというものをreducerに含めておく必要があります。

import * as counterReducers from './counterReducers';
import * as Redux from 'redux';
import * as ReactRouterRedux from 'react-router-redux';
import Counter from '../models/Counter';

export interface AppState {
    counter: Counter
}

export const reducer = Redux.combineReducers({
    counter: counterReducers.reducer,
    routing: ReactRouterRedux.routeReducer
});

middlewareの設定

続けて、何か拡張的なことやるならお約束のmiddlewareを設定します。 syncHisotryにアプリで使うhistoryを渡してやればmiddlewareが出来上がるのでapplyMiddlewareしてやればOKです。

import * as Redux from 'redux';
import * as ReactDOM from 'react-dom';
import * as React from 'react';
import {Router, Route, IndexRoute} from 'react-router';
import * as ReactRouterRedux from 'react-router-redux';
import {Provider} from 'react-redux';
import App from './components/App';
import IndexPage from './components/IndexPage';
import NextPage from './components/NextPage';
import * as history from 'history';
import * as reducers from './reducers';

const browserHistory = history.createHashHistory();
const createStoreWithMiddleware = Redux.applyMiddleware(ReactRouterRedux.syncHistory(browserHistory))(Redux.createStore);
const store = createStoreWithMiddleware(reducers.reducer);

const router = (
    <Router history={browserHistory}>
        <Route path='/' component={App}>
            <IndexRoute component={IndexPage} />
            <Route path='/next' component={NextPage} />
        </Route>
    </Router>
);

ReactDOM.render(
    <Provider store={store}>
        {router}
    </Provider>,
    document.getElementById('content'));

画面遷移

画面遷移用のアクションが定義されています。

push, goBack, goFowardあたりを覚えておけばよさそうです。使い方は普通のアクションと同じで、dispatch(ReactRouterRedux.push('/pathtopage'));のようにするかconnectの第二引数でマッピングしてやるかしてやればOKです。

ボタンを押したら/nextというページにパラメータ渡して遷移するような感じのコードは以下のようになります。

import * as React from 'react';
import * as ReactRouter from 'react-router';
import * as ReactRedux from 'react-redux';
import * as reducers from '../reducers';
import * as ReactRouterRedux from 'react-router-redux';
import * as counterActions from '../actions/counterActions';

interface IndexPageProps extends ReactRouter.RouteComponentProps<{}, {}> {
    push?: ReactRouterRedux.PushAction;
    increment?: (x: number) => void;
    decrement?: (x: number) => void;
    count?: number;
}

class IndexPage extends React.Component<IndexPageProps, {}> {
    render() {
        const {
            count,
            increment,
            decrement,
            push
        } = this.props;

        return (
            <div>
                <span>{count}</span>
                <br />
                <button onClick={() => increment(1)}>INC</button>
                <button onClick={() => decrement(1)}>DEC</button>
                <hr />
                <button onClick={() => push('/next?count=' + count)}>Go to next page</button>
            </div>
        );
    }
}

function select(state: reducers.AppState): IndexPageProps {
    return {
        count: state.counter.count
    };
}

export default ReactRedux.connect(select, {
    push: ReactRouterRedux.push,
    increment: counterActions.increment,
    decrement: counterActions.decrement
})(IndexPage);

コード全体

コード全体はGitHubに上げています。

github.com