Redux 基礎:Action 編

  • 98
    いいね
  • 0
    コメント
この記事は最終更新日から1年以上が経過しています。

概要

React + Redux の Action についてサンプルを使って、Action の作成と動作の確認をします。

準備

redux/examples/real-world からいろいろそぎ落としたこちらのソースtag/init を使って説明します。
※ 実装完了はtag/action

Action とは

Action はストアの state を変更するためのメッセージです。
Action によって state が変わると UI の表示などアプリの変化が起きるので、アプリに何か起こすための出発点となります。

  1. Action 発行
  2. Reducer が現在の state と action を元に新しい state を作成。
  3. state の変更をUIなどに反映

Action は javascipt のオブジェクトでどのような形でも大丈夫ですが、慣習として type フィールドに文字列で Action のタイプを指定します。 type フィールド以外は自由に定義してください。

{
    type: "SHOW_ERROR",
    error: message
}

Action の作成

今回のサンプルには errorMessage という Reducer があります。

reducer/index.js
function errorMessage(state = null, action) {
  const { type, error } = action;

  if (type === ActionTypes.RESET_ERROR_MESSAGE) {
    return null;
  }

  if (error) {
    return error;
  }

  return state;
}

この Reducer は action.typeRESET_ERROR_MESSAGE のとき、新しい状態として null を返し、actionerror があるとき 新しい状態として error を返します。
アプリはこの状態を UI にエラーメッセージとして表示します。

この Reducer が処理できる Action を発行します。

まず、Action を発行するには ActionCreator を作ります。ActionCreator は Action を返すだけの単純な関数です。
actions/index.js にすでに resetErrorMessage という ActionCreator があるので同じように showErrorMessage を作ります。

actions/index.js
export const SHOW_ERROR_MESSAGE = 'SHOW_ERROR_MESSAGE';

export function showErrorMessage(message) {
  return {
    type: SHOW_ERROR_MESSAGE,
    error: message
  }
}

Action の発行

Action を発行するには、store.dipatch(action) に Action を渡しますが、react-redux の connect を使うと ActionCreator (と同じ形の function) で自動的に発行できます。

containers/App.js にすでに resetErrorMessage のコードがあるので、同じように connectshowErrorMessage を追加します。

containers/App.js
import { resetErrorMessage, showErrorMessage } from '../actions';

export default connect(mapStateToProps, {
  resetErrorMessage,
  showErrorMessage,
  pushState
})(App);

connect が props に showErrorMessage (と同じ形の function)をマッピングするため、その function を呼んで発行します。

containers/App.js
  handleShowError(e) {
    this.props.showErrorMessage("sample error!!");
    e.preventDefault();
  }

  renderSample() {
    return (
      <ul>
        <li><a href="#" onClick={::this.handleShowError}>show error</a></li>
      </ul>
    );
  }

show error のリンクをクリックするとエラーメッセージが表示されます。 エラー表示後の Dissmiss をクリックするとエラーメッセージを消します。
右のペーンで Action と state の変化が確認できます。

bindActionCreators

Action を追加するたびに connect に追加するのはたいへんなので、bindActionCreators を使って自動的にマッピングします。

connect を次のように変更します。

containers/App.js
import { bindActionCreators } from 'redux';
// import { resetErrorMessage, showErrorMessage } from '../actions';  // 削除
import * as Actions from '../actions';

function mapDispatchToProps(dispatch) {
  return {
    ...bindActionCreators(Actions, dispatch),
    pushState
  };
}

export default connect(mapStateToProps, mapDispatchToProps)(App);

非同期の Action

1秒後に何かしたいなど、非同期で Action を実行したい場合は、ActionCreator で function (dipatch) 型の function を返します。

actions/index.js

export function showErrorMessageDelayed(message, delay = 1000) {
  return dispatch => {
    setTimeout(() => {
      dispatch(showErrorMessage(message));
    }, delay);
  };
}

さらに store に thunk という middleware を追加します。

store/configureStore.dev.js
import thunk from 'redux-thunk';

const finalCreateStore = compose(
  applyMiddleware(thunk),
  reduxReactRouter({ routes, createHistory }),
  applyMiddleware(createLogger()),
  DevTools.instrument()
)(createStore);

Action の発行や Reducer は特別な処理はなく同期型と同じです。

containers/App.js
  handleShowErrorDelayed(e) {
    this.props.showErrorMessageDelayed("delayed sample error!!");
    e.preventDefault();
  }

最後に

サンプルで遊んでいるときは簡単だと思いましたが、Action がきちんと通るようにするまでが結構たいへんでした。
一度設定してしまえば、あまり変更しない部分なので自分用のテンプレートができると楽になると思います。

参考