かずきのBlog@hatena

すきな言語は C# + XAML の組み合わせ。Azure Functions も好き。最近は Go 言語勉強中。日本マイクロソフトで働いていますが、ここに書いていることは個人的なメモなので会社の公式見解ではありません。

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