React Redux mapDispatchToProps vs this.props.dispa

2019-02-18 12:32发布

问题:

Until now I used my containers and components actions this way:

<Header btnMnuAction={this.props.toggleSidebar} logout={this.props.logout}/>

With the mapDispatchToProps function:

const mapDispatchToProps = (dispatch) => {
    return {
        toggleSidebar: () => {
            dispatch(toggleSidebar());
        },
        logout: () => {
            dispatch(logout());
        }
    }
};

Now I tried it this way:

<Header btnMnuAction={() => this.props.dispatch(toggleSidebar())} logout={() => this.props.dispatch(logout())} >

Please, can someone explain to me what's the difference between these options?

Thanks :)

回答1:

When you use connect from redux and make use of mapDispatchToProps, the functions returned by the mapDispatchToProps are available as props, for example in the first case

const mapDispatchToProps = (dispatch) => {
    return {
        toggleSidebar: () => {
            dispatch(toggleSidebar());
        },
        logout: () => {
            dispatch(logout());
        }
    }
};

From the props you will have access to toggleSidebar and logout, which internally have the dispatch defined on them.

In the second case, if you don't pass the second argument to connect, it makes the dispatch available to you by default and then you can call the action using dispatch

So these are just two different ways to achieve the same result and internally doing the same thing.



回答2:

The base role of mapDispatchToProps is exactly what you do inline in your example, however, it is more flexible as it can accept not only the dispatcher but the target component's state and own props.

You can use these extra parameters to change behavior based on component state (for example if it is disabled then you may return no bound actions) or props (for example, if there is cleanStorage in own props of the component, pass it along the logout action).

Using mapDispatchToProps makes your code cleaner and better separated. Imagine passing 10+ actions and binding them manually... Consumer components should only accept defined actions, not a generic dispatch and by that, it reduces coupling to the Redux and allows for easier maintenance and testing.

By using some advanced features you can define simpler function bind, where you just bind the dispatch function to the action creators, for example like this:

const bind => actions => dispatch => 
  Object.entries(actions)
  .map(([key, action]) => [key, (...args) => dispatch(action(...args)])
  .reduce((acc, ([key, boundAction]) => ({...acc, [key]: boundAction}), {})

connect(mapStateToProps, bind( { toggleSidebar, logout } ), ...)(Component)

Or just use bindActionCreators(actionCreators, dispatch) to reduce boilerplate:

import { bindActionCreators } from 'redux';

connect(
  mapStateToProps,
  dispatch => bindActionCreators( { toggleSidebar, logout }, dispatch),
  ...
)(Component)


回答3:

Actually, there is no significant difference. Only difference I can think of is that the first approach create a new inline function each time render method get called. Other than that, those are just different ways to do the same thing.

There is another less coding and cleaner approach for mapDispatchToProps. If you only just call a function inside the dispatch call in mapDispatchToProps you can avoid it all together and directly pass your methods in a object as the second argument of connect method.

connect(mapStateToProps, {toggleSidebar, logout})(Component)