Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How does mapDispatchToProps work in react-redux

I watched the egghead.io tutorial on Redux and feel like I have some sense of what Redux is trying to do, but the way it actually works is still mysterious to me. I implemented Dan's simple counter app using the react-redux connect method, but I don't really understand my implementation. There are two possible ways I tried:

Without passing dispatch:

const mapDispatchToProps = {
  upIt: () => {
    return ({type:'INCREMENT'}
  )
  },
  downIt: () => {
    return({type:'DECREMENT'})
  }
}

Passing dispatch:

const mapDispatchToProps = dispatch => ({
  upIt: () => {
    dispatch({type:'INCREMENT'}
  )
  },
  downIt: () => {
    dispatch({type:'DECREMENT'})
  }
})

The counter works using either or those two options, but I am not sure how the first option (where I never call 'dispatch') manages to hook up to the store.dispatch method. Is there any reason I should prefer one way of writing the method over the other?

like image 479
wbruntra Avatar asked Jul 18 '17 14:07

wbruntra


2 Answers

Think of mapDispatchToProps as an interface that passes relevant action creators to your component (these action creators appear on, and are accessed within your component as props).

Action creators are NOT the same as actions.

In Redux, an action is simply a plain JavaScript object such as the following (it can have whatever properties you want but must include the type property):

{ type: 'INCREMENT' }

These actions are sent to the reducer, which handles how to update the state based on the actions properties.

An action creator is a function that sends these actions to the reducer when called.

So, in your examples, upIt and downIt are action creators, while {type:'INCREMENT'} and {type:'DECREMENT'} are actions.

Take upIt for example:

upIt: () => {
    return ( {type:'INCREMENT'} )
}

The connect() function from react-redux will intercept the action returned from this action creator function, and dispatch it to the redux store (it will then be handled by the reducer).

connect function implementation:

connect(mapStateToProps, mapDispatchToProps)(ComponentName)

However, consider the case where you might want to dispatch multiple actions from a single action creator. How would this be possible, when a function can only return a value once?

This is where the dispatch parameter of mapDispatchToProps comes in! It allows you to dispatch multiple actions from a single action creator.

For example, say you want to create a button in the UI to increment the counter, then 5 seconds later, decrement it again. Your action creator defined in mapDispatchToProps might look something like this:

const mapDispatchToProps = dispatch => ({
    incrementForFiveSeconds: () => {
        dispatch( {type:'INCREMENT'} );
        setTimeout(() => { 
            dispatch( {type:'DECREMENT'} );
        }, 5000);
    },
    // other action creators
})

Notice how we can call the dispatch function twice within the same action creator!

To summarize:

  1. If your action creator will only dispatch a single action, then you can use either the return or the dispatch() interface.
  2. If your action creator may need to dispatch multiple action creators, then you will need to use the dispatch() interface.
like image 135
cathalkilleen Avatar answered Sep 21 '22 22:09

cathalkilleen


From the Redux documentation docs:

[mapDispatchToProps(dispatch, [ownProps]): dispatchProps] (Object or Function):

If an object is passed, each function inside it is assumed to be a Redux action creator. An object with the same function names, but with every action creator wrapped into a dispatch call so they may be invoked directly, will be merged into the component’s props. If a function is passed, it will be given dispatch. If you don't want to subscribe to store updates, pass null or undefined in place of mapStateToProps. It’s up to you to return an object that somehow uses dispatch to bind action creators in your own way. (Tip: you may use the bindActionCreators() helper from Redux.) If you omit it, the default implementation just injects dispatch into your component’s props. If ownProps is specified as a second argument, its value will be the props passed to your component, and mapDispatchToProps will be re-invoked whenever the component receives new props.

In the first case

const mapDispatchToProps = {
  upIt: () => {
    return ({type:'INCREMENT'}
  )
  },
  downIt: () => {
    return({type:'DECREMENT'})
  }
}

mapDispatchToProps is a object and thus upIt and downIt are assumed to be action creators.

In the second case:

const mapDispatchToProps = dispatch => ({

    upIt: () => {
        dispatch({type:'INCREMENT'}
      )
      },
      downIt: () => {
        dispatch({type:'DECREMENT'})
      }
    })

mapDispatchToProps is a function and thus each function inside it must be passed to dispatch

like image 21
Shubham Khatri Avatar answered Sep 17 '22 22:09

Shubham Khatri