4
votes

Redux-thunk allows you to create action-creators that return a function instead of an action. The inner function receives the store methods dispatch and getState as parameters.

function incrementAsync() {
  return (dispatch, getState) => {
    setTimeout(() => {
       dispatch(increment());
    }, 1000);
  };
}

But at the same time, react-redux' connect already has a mapDispatchToProps argument that can be used to wrap action creator into a dispatch call so they may be invoked directly. With mapDispatchToProps you can already do,

const mapDispatchToProps = (dispatch) => ({
  incrementAsync: () => {
    setTimeout(() => {
      dispatch(increment());
    }, 1000);
  }
});
export default connect(mapStateToProps, mapDispatchToProps)(MyComponent)

In my eyes, the same can be accomplished without redux-thunk. Why do we have the redux-thunk library in the first place? I'm sure I'm just failing to see it since redux-thunk is a fairly popular library.

5

5 Answers

0
votes

In short your solution is totally fine.

I think the convenience of using thunk middleware would be that you could treat any action creator call async or not the same way, meaning you don't have to pass the dispatch function around. Whenever what you dispatch is a function dispatch is injected into its returning function. To sum up, using redux-thunk makes action creators composable.

See Dan Abramovs detailed answer here: How to dispatch a Redux action with a timeout?

Also just looking at the redux-thunk code helped me understand this.

0
votes

Aside from Redux Thunk, there are two big advantages to the first example:

  1. It's easier to test as it's isolated and functional, so you just need to include it and use in order to assert it behaves correctly (no prop querying, simulating or problems with shallow rendering that you'll have if it's in a component)
  2. It's possible to re-use it (the second example is impossible to re-use). Imagine you have to dispatch the same action from several places in the app and use the second pattern, duplicating the code, then the requirements for the action change?
0
votes

It's true that you can access dispatch from your action this way but redux-thunk makes it possible without that wrapper function and explicit dispatch handoff.

You also get immediate access to the state from your action through the getState() function provided as the second parameter.

// actionFile.js
export someAction(dispatch) {
  return function(value) {
    dispatch({ type: 'SOME_TYPE', value });
  }
}

// component.jsx
const mapDispatchToProps = (dispatch) => ({
  someAction: someAction(dispatch)
});

vs.

// actionFile.js
export someAction(value) {
  return function(dispatch, getState) {
    dispatch({ type: 'SOME_TYPE', value });
    // maybe do some stuff with getState()
  }
}

// component.jsx
const mapDispatchToProps = { someAction };

It's definitely optional, but a lot cleaner in my opinion, and most importantly provides a better separation of concerns between your component and action creators. I.e., you don't need to fuss with how you define your mapDispatchToProps when at some point down the line you need to dispatch asynchronously or trigger side effects.

0
votes

Action creators can be synchronous or asynchronous. redux-thunk is mainly used to create asynchronous action creators like sending an API call, in which an asynchronous action creator dispatches another function/action creator instead of returning just an action. The inner function receives store methods dispatch and getState as parameters.

  1. Wrapping the action creator into a dispatch call in mapDispatchToProps does not provide access to getState method. redux-thunk provides access to both, dispatch as well as getState.

    export const actionCreator = () => {
        return (dispatch, getState) => {
        //axios call
        dispatch(anotherActionCreator());
      };
    };
    
  2. Using action creator in mapDispatchToProps conflicts with encapsulation and consistency of using action creators as the component doesn't have to know about the details of creating and dispatching the action whether its a simple return of an action object or a complex redux-thunk asynchronous action creator.

  3. Creating action creators separately helps us to reuse the action creator at multiple places.

0
votes

One big advantage of using redux-thunk is being able to access the entire state when determining the action, something that is impossible to do using only mapDispatchToProps.

It may seem weird that you can't just get the whole state in mapDispatchToProps in the first place, but it makes sense since mapDispatchToProps is probably only called once on first render, and thus any state passed to it might be stale by the time one of the actions gets called.

So you can either use redux-thunk, or instead pass the entire pieces of state you need to the component as props to determine your action, which in some situations might be useless to render your component, thus triggering unnecessary and possibly costly re-renders, just so your component can work as a bridge to pass data to the action creator.