Redux-thunk で非同期にアクションを発行する

https://codesandbox.io/s/ovv2o75mr5

Action Creator の中で非同期処理がうまく書けない… Redux-thunk を使う

次のように Action Creator の中でアクションを非同期に返しても、うまくいきません。ですので 「Redux-thunk」 をミドルウェアとして使用する必要があります。

うまくいかない例

actions/index.js

export const asyncMinus = num => {
  setTimeout(() => {
    return { type: "MINUS", payload: { num: num } };
  }, 1000);
};

index.js で redux-thunk を middleWare として適用する

index.js

import React from "react";
import { render } from "react-dom";

// store に middleWare を適用するための関数
// applyMiddleware を import する
import { createStore, applyMiddleware } from "redux";
import rootReducer from "./reducers";

import { Provider } from "react-redux";

import App from "./containers/App";

// redux-thunk
import thunk from "redux-thunk";

// 後々複数の middleWare を適用できるように配列に入れる
const middleWares = [thunk];

// createStore の第二引数に、
// applyMiddleware() を使って、middleWare を適用する
const store = createStore(rootReducer, applyMiddleware(...middleWares));

render(
  <Provider store={store}>
    <App />
  </Provider>,
  document.getElementById("root")
);

重要 関数を返すアクションクリエイターを作る

actions/index.js

これは Action Creator ですが、 action そのものを返すのではなく 、 「内部でアクションを dispatch する 関数 」を返してあげます。関数が dispatch されてくると、middleWare に使われている redux-thunk が見つけて、対応してくれます。

// (dispatch) => {} という関数を返すようにする
// この中で dispatch(action) をすればよい
export const asyncMinus = num => {
  return dispatch => {
    setTimeout(() => {
      dispatch({ type: "MINUS", payload: { num: num } });
    }, 1000);
  };
};

コンポーネント、コネクトの修正

containers/App.js

import App from "../components/App";
import { connect } from "react-redux";

// 作った action である asyncMinus を読み込む
import { minus, plus, asyncMinus } from "../actions";

const mapStateToProps = state => {
  return {
    number: state.number,
    day: state.day,
    title: state.title
  };
};

const mapDispatchToProps = dispatch => {
  return {
    plus: num => {
      dispatch(plus(num));
    },
    minus: num => {
      dispatch(minus(num));
    },
    asyncMinus: num => {
      // 渡す
      dispatch(asyncMinus(num));
    }
  };
};

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

components/App.js

import React from "react";

// asyncMinus を受け取る
const App = ({ number, day, title, plus, minus, asyncMinus }) => (
  <div>
    <h2>
      {title} {number} {day}
    </h2>
    <button
      onClick={() => {
        plus(10);
      }}
    >
      + 10
    </button>
    <button
      onClick={() => {
        minus(10);
      }}
    >
      - 10
    </button>
    <button
      onClick={() => {
        // 実行する
        asyncMinus(10);
      }}
    >
      async - 10
    </button>
  </div>
);

export default App;

Last updated