Using thunks in mapDispatchToProps

2020-07-10 05:51发布

问题:

I'm wondering how to use async action creators in mapDispatchToProps for react-redux's connect. I'm using the redux-thunk middleware and the following is my mapDispatchToProps:

function mapDispatchToProps(dispatch) {
    return {
        foo: function() {
            dispatch(someAction());

            return function asyncAction(dispatch, getState) {
                console.log("An async action!");
                dispatch(someOtherAction(getState().foo));
            };
        }
    }
}

However, when I do the above, the async action does not get executed. What is the correct way to do this?

回答1:

I suggest declaring your actual thunk (someOtherAction) differently. In the following example, asyncAction is an async action creator which returns a thunk. The thunk can then dispatch other actions (after a promise resolves for example).

function asyncActionCreator () {
  return (dispatch, getState) => {
    dispatch(someAction());

    someAsyncStuff().then(() => {
      dispatch(someOtherAction(getState().foo);
    });
  }
}

function mapDispatchToProps(dispatch) {
  return {
    foo: () => dispatch(asyncActionCreator())
  }
}


回答2:

For completeness I'm going to add this. I needed to dispatch 2 actions using 1 action creator but the second action was depending on the result of the first. The second action also needed access to a different slice of the store so I couldn't use the same reducer I was using to set the first value.

My mapDispatchToProps, using redux-thunk, ended up looking as follow:

import constants from '../constants';

const mapDispatchToProps = (dispatch) => {
    return {
        setValuesToStore: (value) => {
            const firstAction = {
                type: constants.SET_FIRST_VALUE,
                value,
            }
            dispatch(firstAction)
            dispatch(secondAction())
            function secondAction() {
                return (dispatch, getState) => {
                    const state = getState()
                    dispatch({
                        type: constants.SET_SECOND_VALUE,
                        state,
                    })
                }
            }
        }
    }
}

This way I didn't need to import the store as a module, which I found very ugly. No biggie, just hope this helps.



回答3:

Although the accepted answer is clearly preferable, I believe this small modification to your code might also help to understand how this mechanism works:

function mapDispatchToProps(dispatch) {
    return {
        foo: () => dispatch(function() { // <-- Note the dispatch!
            dispatch(someAction());

            return function asyncAction(dispatch, getState) {
                console.log("An async action!");
                dispatch(someOtherAction(getState().foo));
            };
        }()) // <-- Note the IIFE!
    }
}

Your original thunk-creating function (associated with foo) here must actually be immediately invoked and dispatch'ed, for this pattern to work.