ChatGPT解决这个技术问题 Extra ChatGPT

What is mapDispatchToProps?

I was reading the documentation for the Redux library and it has this example:

In addition to reading the state, container components can dispatch actions. In a similar fashion, you can define a function called mapDispatchToProps() that receives the dispatch() method and returns callback props that you want to inject into the presentational component.

This actually makes no sense. Why do you need mapDispatchToProps when you already have mapStateToProps?

They also provide this handy code sample:

const mapDispatchToProps = (dispatch) => {
  return {
    onTodoClick: (id) => {
      dispatch(toggleTodo(id))
    }
  }
}

What is this function and why it is useful?


S
Sridhar

I feel like none of the answers have crystallized why mapDispatchToProps is useful.

This can really only be answered in the context of the container-component pattern, which I found best understood by first reading:Container Components then Usage with React.

In a nutshell, your components are supposed to be concerned only with displaying stuff. The only place they are supposed to get information from is their props.

Separated from "displaying stuff" (components) is:

how you get the stuff to display,

and how you handle events.

That is what containers are for.

Therefore, a "well designed" component in the pattern look like this:

class FancyAlerter extends Component {
    sendAlert = () => {
        this.props.sendTheAlert()
    }

    render() {
        <div>
          <h1>Today's Fancy Alert is {this.props.fancyInfo}</h1>
          <Button onClick={sendAlert}/>
        </div>
     }
}

See how this component gets the info it displays from props (which came from the redux store via mapStateToProps) and it also gets its action function from its props: sendTheAlert().

That's where mapDispatchToProps comes in: in the corresponding container

// FancyButtonContainer.js

function mapDispatchToProps(dispatch) {
    return({
        sendTheAlert: () => {dispatch(ALERT_ACTION)}
    })
}

function mapStateToProps(state) {
    return({fancyInfo: "Fancy this:" + state.currentFunnyString})
}

export const FancyButtonContainer = connect(
    mapStateToProps, mapDispatchToProps)(
    FancyAlerter
)

I wonder if you can see, now that it's the container 1 that knows about redux and dispatch and store and state and ... stuff.

The component in the pattern, FancyAlerter, which does the rendering doesn't need to know about any of that stuff: it gets its method to call at onClick of the button, via its props.

And ... mapDispatchToProps was the useful means that redux provides to let the container easily pass that function into the wrapped component on its props.

All this looks very like the todo example in docs, and another answer here, but I have tried to cast it in the light of the pattern to emphasize why.

(Note: you can't use mapStateToProps for the same purpose as mapDispatchToProps for the basic reason that you don't have access to dispatch inside mapStateToProp. So you couldn't use mapStateToProps to give the wrapped component a method that uses dispatch.

I don't know why they chose to break it into two mapping functions - it might have been tidier to have mapToProps(state, dispatch, props) IE one function to do both!

1 Note that I deliberately explicitly named the container FancyButtonContainer, to highlight that it is a "thing" - the identity (and hence existence!) of the container as "a thing" is sometimes lost in the shorthand

export default connect(...) ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀

syntax that is shown in most examples


I would still like to know: What about the required functionality could not be handled by directly calling store.dispatch from within a component?
@user2130130 None. It's about good design. If you coupled your component to store.dispatch, then when you decide to factor out redux, or want to use it some place that isn't redxu based (or some other thing I can't think of now) you are stuck with a lot of changes. Your question generalises to "why do we bother with 'good design practices' - you get the same functionality however you code it". mapDispatchToProps is provided so you can write well designed, cleanly decoupled components.
What I really don't get here is what is: ALERT_ACTION is that the action function or the type that is returned from the action function? :/ so baffed
@JamieHutber Strictly, ALERT_ACTION has nothing to do with this question. It is a valid argument to dispatch, and as it happens, in my code it comes from an "action builder", which returns an object that dispatch uses, as described redux.js.org/docs/api/Store.html#dispatch. The main point here is that how to call dispatch is described in the container and passed in on the components props. The component only gets functions from its props, nowhere else. The "wrong" way of doing it in this pattern would be to pass dispatch to the component and make that same call in the component.
If you have multiple action creators that need to be passed to child component as props, one alternative is to wrap them with bindActionCreators inside mapDispatchToProps (see redux.js.org/docs/api/bindActionCreators.html); another alternative is to simply provide an object of action creators to connect(), eg, connect(mapStateToProps, {actioncreators}),react-redux will wrap them with dispatch() for you.
S
Sabito 錆兎 stands with Ukraine

It's basically a shorthand. So instead of having to write:

this.props.dispatch(toggleTodo(id));

You would use mapDispatchToProps as shown in your example code, and then elsewhere write:

this.props.onTodoClick(id);

or more likely in this case, you'd have that as the event handler:

<MyComponent onClick={this.props.onTodoClick} />

There's a helpful video by Dan Abramov on this here: Redux: Generating Containers with connect() from React Redux (VisibleTodoList)


Thank you. I'm also wondering, how does dispatch get added to the props in the first place?
If you don't provide your own mapDispatch function, Redux will use a default. That default mapDispatch function simply takes the dispatch function reference, and gives it to you as this.props.dispatch.
The dispatch method is passed down by the Provider Component
C
Code Whisperer

mapStateToProps() is a utility which helps your component get updated state(which is updated by some other components),
mapDispatchToProps() is a utility which will help your component to fire an action event (dispatching action which may cause change of application state)


M
Mayank Pandeyz

mapStateToProps, mapDispatchToProps and connect from react-redux library provides a convenient way to access your state and dispatch function of your store. So basically connect is a higher order component, you can also think as a wrapper if this make sense for you. So every time your state is changed mapStateToProps will be called with your new state and subsequently as you props update component will run render function to render your component in browser. mapDispatchToProps also stores key-values on the props of your component, usually they take a form of a function. In such way you can trigger state change from your component onClick, onChange events.

From docs:

const TodoListComponent = ({ todos, onTodoClick }) => (
  <ul>
    {todos.map(todo =>
      <Todo
        key={todo.id}
        {...todo}
        onClick={() => onTodoClick(todo.id)}
      />
    )}
  </ul>
)

const mapStateToProps = (state) => {
  return {
    todos: getVisibleTodos(state.todos, state.visibilityFilter)
  }
}

const mapDispatchToProps = (dispatch) => {
  return {
    onTodoClick: (id) => {
      dispatch(toggleTodo(id))
    }
  }
}

function toggleTodo(index) {
  return { type: TOGGLE_TODO, index }
}

const TodoList = connect(
  mapStateToProps,
  mapDispatchToProps
)(TodoList) 

Also make sure that you are familiar with React stateless functions and Higher-Order Components


So dispatch is like event basically?
It could be related to event, dispatch is just a function and the only way to change your application state. mapStateToProps is one way to expose dispatch function of your store to React Component. Also note that connect is not a part of redux in fact it is just a utility and boilerplate reduce library called react-redux to work with react and redux. You can achieve the same result without react-redux if you pass your store from root react component to children.
M
Meet Zaveri

Now suppose there is an action for redux as:

export function addTodo(text) {
  return {
    type: ADD_TODO,
    text
  }
}

When you do import it,

import {addTodo} from './actions';

class Greeting extends React.Component {

    handleOnClick = () => {
        this.props.onTodoClick(); // This prop acts as key to callback prop for mapDispatchToProps
    }

    render() {
        return <button onClick={this.handleOnClick}>Hello Redux</button>;
    }
}

const mapDispatchToProps = dispatch => {
    return {
      onTodoClick: () => { // handles onTodoClick prop's call here
        dispatch(addTodo())
      }
    }
}

export default connect(
    null,
    mapDispatchToProps
)(Greeting);

As function name says mapDispatchToProps(), map dispatch action to props(our component's props)

So prop onTodoClick is a key to mapDispatchToProps function which delegates furthere to dispatch action addTodo.

Also if you want to trim the code and bypass manual implementation, then you can do this,

import {addTodo} from './actions';
class Greeting extends React.Component {

    handleOnClick = () => {
        this.props.addTodo();
    }

    render() {
        return <button onClick={this.handleOnClick}>Hello Redux</button>;
    }
}

export default connect(
    null,
    {addTodo}
)(Greeting);

Which exactly means

const mapDispatchToProps = dispatch => {
    return {
      addTodo: () => { 
        dispatch(addTodo())
      }
    }
}

S
Sabito 錆兎 stands with Ukraine

mapStateToProps receives the state and props and allows you to extract props from the state to pass to the component.

mapDispatchToProps receives dispatch and props and is meant for you to bind action creators to dispatch so when you execute the resulting function the action gets dispatched.

I find this only saves you from having to do dispatch(actionCreator()) within your component thus making it a bit easier to read.

React redux: connect: Arguments


Thank you but what is the value of the dispatch method? Where does it come from?
oh. Dispatching basically makes the action start the redux/flux unidirectional flow. The other answers seem to have answered your question better than this.
Also, the dispatch method comes from the enhancement provided by the <Provider/> itself. It does its own high order component magic in order to guarantee that dispatch is available in its children components.