What is mapDispatchToProps? - reactjs

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?

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

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)

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)

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

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())
}
}
}

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

Related

What is going on in this Redux code...confused about mapDispatchToProps, dispatch, and connect

I'm following a react tutorial and I had a few questions.
I am confused about this function:
function mapDispatchToProps(dispatch) {
return bindActionCreators({ fetchWeather }, dispatch)
}
I want to breakdown each part of this function.
How do you hook up the action creator to a container? How is this.props.fetchWeather working code? Is this responsible for that?:
function mapDispatchToProps(dispatch) {
If so, what is this doing?
return bindActionCreators({ fetchWeather }, dispatch)
Is that responsible for making sure that the action object that is returned from the action creator flows down into the middleware and reducers?
What is this doing then:
function mapDispatchToProps(dispatch)
Is mapDispatchToProps just convention or is it part of react?
Lastly, what is this export doing:
export default connect(null, mapDispatchToProps)(SearchBar);
What is the connect doing? What does it do for me?
Here is my whole code for reference:
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';
import { fetchWeather } from '../actions/index';
class SearchBar extends Component {
constructor(props) {
super(props);
this.state = { term: '' };
this.onInputChange = this.onInputChange.bind(this);
this.onFormSubmit = this.onFormSubmit.bind(this);
}
onInputChange(event) {
this.setState({ term: event.target.value });
}
onFormSubmit(event) {
event.preventDefault();
this.props.fetchWeather(this.state.term);
this.setState({ term: '' });
}
render() {
return (
<form onSubmit={this.onFormSubmit} className="input-group">
<input
placeholder="Get a five-day forecast in your favorite cities"
className="form-control"
value={this.state.term}
onChange={this.onInputChange}
/>
<span className='input-group-btn'>
<button type="submit" className="btn btn-secondary">
Submit
</button>
</span>
</form>
);
}
}
function mapDispatchToProps(dispatch) {
return bindActionCreators({ fetchWeather }, dispatch)
}
export default connect(null, mapDispatchToProps)(SearchBar);
A very concise answer would be:
mapStateToProps() is a utility which helps your component gets 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 a change of application state)
bindActionCreators() is mostly used when you want to pass some action creators down to a component that isn't aware of Redux, and you don't want to pass dispatch or the Redux store to it.
<Provider> makes the Redux store available to the your "connected" React components.
connect() is a higher-order component (HOC) that lets you inject Redux state into a regular React component.
Let's dive a bit deeper
ReactJS - JS library for building user interfaces.
Redux - JS library for managing application state.
Putting them together using react-redux:
If we want to link our React application with the Redux store, we first have to let our app know that this store exists. This is where we come to the first major part of the react-redux library, which is the Provider.
A Provider is a React component given to us by the react-redux library. It serves just one purpose: to “provide” the store to its child components.
Provider
Makes the Redux store available to the connect() calls in the component hierarchy below. Normally, you can’t use connect() without wrapping a parent or ancestor component in <Provider>. So ultimately connect does just that, it connects your React app to the Redux store.
//This is the store we create with redux's createStore method
const store = createStore(todoApp, {})
// Provider is given the store as a prop
render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById('app-node')
)
Props
store (Redux Store): The single Redux store in your application.
children (React Element): The root of your component hierarchy.
Explanation and usage of the Connect function:
Now that we have “provided” the redux store to our application, we can now connect our components to it. We established previously that there is no way to directly interact with the store. We can either retrieve data by obtaining its current state or change its state by dispatching an action (we only have access to the top and bottom component of the redux flow diagram shown previously). This is precisely what connect() does.
To use connect(), you need to define a special function called mapStateToProps that describes how to transform the current Redux store state into the props you want to pass to a presentational component you are wrapping.
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.
Simple explanation and a basic example of mapStateToProps
The Store is a box, which contains the entire application state. Imagine that this box is in an unknown location.
The components need to take some of the things out of the box but they only need some of the things stored in it. The components know what they need from the box but they don't know where the box is.
The mapStateToProps function is a filter used to select which things in the box are required by the component. The selected things become the component properties.
The mapStateToProps function is not enough because it selects the required things in the box but it doesn't know where the box is located.
The connect function knows where the box is located and passes it to the mapStateToProps function so it can grab what it needs.
Conclusion: mapStateToProps simply returns a specified part of the current state. mapStateToProps get the data that is fed to its component.
const mapStateToProps = (state) => {
return { things: state.things }
};
So now we're able to use that part of the state as props -> this.props.things
But what if the component wants to change the state? That is where mapDispatchToProps comes in.
Simple explanation and a basic example of mapDispatchToProps
As implied in its name, this function directs the dispatching or sending of an action by pointing it to an action creator. For example:
const mapDispatchToProps = () => {
return {
addThing: addThing,
doAnotherThing: doAnotherThing
}
}
mapDispatchToProps takes the dispatch functions in your component and executes them against the Redux reducer when that function is fired. Remember that Props aren’t just objects, they can also be functions. This is where mapDispatchtoProps applies. MapDispatchToProps allows for you to dispatch state changes to your store. An example would be a button click that triggers a refresh or an automatic loading of data once the component is mounted.
The action creator is made available to the component as a prop, which is usually tied to an event handler function contained in the component:
handleOnClick() {
this.props.addThing();
};
However, returning the action creator is only one part. We also want the send that returned action to the store. How do we do that? We use Redux’s bindActionCreators().
Simple explanation and a basic implementation of bindActionCreators():
Turns an object whose values are action creators, into an object with the same keys, but with every action creator wrapped into a dispatch call so they may be invoked directly.
Normally you should just call dispatch directly on your Store instance. If you use Redux with React, react-redux will provide you with the dispatch function so you can call it directly, too.
The only use case for bindActionCreators is when you want to pass some action creators down to a component that isn't aware of Redux, and you don't want to pass dispatch or the Redux store to it.
To implement it, we:
import { bindActionCreators } from 'redux';
...
const mapDispatchToProps = (dispatch) => {
return bindActionCreators({
addThing: addThing,
doAnotherThing: doAnotherThing
}, dispatch);
};
The bindActionCreators() function accepts the action creator and the store’s dispatch function as arguments, and returns a dispatch function that uses the return value of the action creator as its arguments.
Once again, tying this all together is the connect() function, in which we pass mapDispatchToProps as a second argument. For example:
export default connect(mapStateToProps, mapDispatchToProps)(MyComponent);
which will export a component that can both get the current state from the store, and dispatch an action to the store to trigger and update to the state.
Now, let's put it all together with a little TodoItem.js React functional component:
import { connect } from 'react-redux'
const TodoItem = ({ todo, destroyTodo }) => {
return (
<div>
{todo.text}
<span onClick={destroyTodo}> x </span>
</div>
)
}
const mapStateToProps = state => {
return {
todo: state.todos[0]
}
}
const mapDispatchToProps = dispatch => {
return {
destroyTodo: () =>
dispatch({
type: 'DESTROY_TODO'
})
}
}
export default connect(
mapStateToProps,
mapDispatchToProps
)(TodoItem)
mapStateToProps and mapDispatchToProps are both pure functions that are provided the stores “state” and “dispatch” respectively. Furthermore, both functions have to return an object, whose keys will then be passed on as the props of the component they are connected to.
In this case, mapStateToProps returns an object with only one key: “todo”, and mapDispatchToProps returns an object with the destroyTodo key.
The exported connected component provides todo and destroyTodo as props to TodoItem functional component

mapStateToProps vs mapDispatchToProps [duplicate]

This question already has answers here:
What is mapDispatchToProps?
(6 answers)
Closed 4 years ago.
What's the difference between mapStateToProps and mapDispatchToProps arguments to the connect function in react-redux?
mapStateToProps is a function that you would use to provide the store data to your component, whereas mapDispatchToProps is something that you will use to provide the action creators as props to your component.
According to the docs:
If mapStateToProps argument is specified, the new component will
subscribe to Redux store updates. This means that any time the store
is updated, mapStateToProps will be called. The results of
mapStateToProps must be a plain object, which will be merged into
the component’s props.
With mapDispatchToProps every action creator wrapped into a dispatch
call so they may be invoked directly, will be merged into the
component’s props.
A simple example would be
function mapStateToProps(state) {
return { todos: state.todos }
}
function mapDispatchToProps(dispatch) {
return { addTodo: bindActionCreators(addTodo, dispatch) }
}
export default connect(mapStateToProps, mapDispatchToProps)(Todos);
In a very simple term,
mapStateToProps: It connects redux state to props of react component.
mapDispatchToProps: It connects redux actions to react props.
A really light example: ( I hope, you know what I mean)
// state
const mapStateToProps = state => {
return { lists: state.lists };
};
// props
const mapDispatchToProps = ({ lists }) => (
<ul>
{
lists.map(el => (
<li key={ el.id }>
{ el.heading }
</li>
)
}
</ul>
);
// Now, connect state to prop
const List = connect(mapStateToProps)(mapDispatchToProps);
In very simple terms:
mapStateToProps is called when you want to get the value of the global state from your component
function mapStateToProps(state) {
return {
message: state.message
};
}
The value of the global state is only changed with the help of an action. So if you want to change the value of global state you need an action. mapDispatchToProps is used to bind action in your component.

How do I dispatch an action from a Container method in Redux?

I'm new to Redux and I have this question that I can't solve by myself.
I created a TODO list app and now I need to add a new task to the list. The user writes something in a text input and when he clicks the button the new task must be appended to the list.
I already get a 'ADD TASK' action. But I don't know how to call it from inside a component method. So I added an event listener to the button, but when I click it what should I do next?
class List extends React.Component{
addTask(e){
var title = $('[name=title]');
title.val('');
//what should I do?
}
render(){
const mappedTasks = this.props.tasks.map(function(task){
return (
<li key={task.title}>{task.title}</li>
);
});
return (
<div>
<ul>
{mappedTasks}
</ul>
<input name='title' />
<button onClick={this.addTask}>Adicionar</button>
</div>
);
};
}
const mapStateToProps = function(state,ownProps){
return {
message: 'Hello World!',
tasks: state.tasks
}
}
const ListComponent = connect(
mapStateToProps
)(List);
In this example I want to dispatch something from the addTask method.
So what is the proper way of dispatching from a Component method on Redux?
#edit this did the trick:
In render function
<button onClick={this.addTask.bind(this)}>Adicionar</button>
So as Brandon said I could use in the method
this.props.dispatch({type:'ADD_TASK', payload: {title: title.value}});
I see a couple of possible solutions, and which one is more appropriate might depend on your particular use case. There are a few questions that might help:
Is this List component connect-ed to the redux store (using the connect() decorator from the react-redux package? If so, you
should be able to dispatch an action as simply as this:
this.props.dispatch(someActionCreator()).
Are you open to connect-ing this component to the store? If so, decorate the List component like so: connect(mapStateToProps, mapDispatchToProps)(List). Then you'll have access to dispatch() on props in the List component and can proceed just as in question 1.
Does the List component have an ancestor with access to the dispatch() function. If so, you can create an action dispatching function at that level and pass it down as a prop until you reach the List component, where you can call that function.
As I said, your particular use case will determine the suitability of each approach. If you have any more questions, I'm happy to help, so let me know.
Can use something like this.
import { Component } from 'react'
import { bindActionCreators } from 'redux'
import { connect } from 'react-redux'
import * as TodoActionCreators from './TodoActionCreators'
console.log(TodoActionCreators)
// {
// addTodo: Function,
// removeTodo: Function
// }
class TodoListContainer extends Component {
componentDidMount() {
// Injected by react-redux:
let { dispatch } = this.props
// Note: this won't work:
// TodoActionCreators.addTodo('Use Redux')
// You're just calling a function that creates an action.
// You must dispatch the action, too!
// This will work:
let action = TodoActionCreators.addTodo('Use Redux')
dispatch(action)
}
render() {
// Injected by react-redux:
let { todos, dispatch } = this.props
// Here's a good use case for bindActionCreators:
// You want a child component to be completely unaware of Redux.
let boundActionCreators = bindActionCreators(TodoActionCreators, dispatch)
console.log(boundActionCreators)
// {
// addTodo: Function,
// removeTodo: Function
// }
return (
<TodoList todos={todos}
{...boundActionCreators} />
)
// An alternative to bindActionCreators is to pass
// just the dispatch function down, but then your child component
// needs to import action creators and know about them.
// return <TodoList todos={todos} dispatch={dispatch} />
}
}
export default connect(
state => ({ todos: state.todos })
)(TodoListContainer)
One most common way to dispatch an action in component is to dispose the action to props using mapDispatchToProps. Then you can dispatch an action from props.
componentWillMount() {
this.props.actions.loadPropImages();
}
function mapDispatchToProps(dispatch) {
return {
actions: bindActionCreators(imageActions, dispatch)
};
}
export default connect(mapStateToProps, mapDispatchToProps)(EditorPage);

dispatch not defined in componentDidMount

I'm looking at the async redux example here:
https://github.com/reactjs/redux/blob/master/examples/async/src/containers/App.js
If I add the following:
function mapDispatchToProps(dispatch) {
return {};
}
export default connect(mapStateToProps,mapDispatchToProps)(App)
Then dispatch is no longer defined in componentDidMount. Why is this? How can I access dispatch here while using mapDispatchToProps?
The connect function automatically passes dispatch to your props if you do not specify a mapDispatchToProps function. With that in mind:
export default connect(mapStateToProps)(App)
And it should work. You can read more about the react-redux bindings in the docs.
If I understand you correctly, you want to call dispatch from the componentDidMount as a function in the this.props (which I don't recommend, check how redux works and create the action creators that you need). Even so, to achieve that you can do that:
function mapDispatchToProps(dispatch) {
return { dispatch };
}
That creates a dispatch property that is the dispatch function itself.
Still, don't do that on a real use case and keep reading about redux action.creators.
Following the given example, you pass mapDispatchToProps to connect like this
function mapDispatchToProps(dispatch) {
return {
onClick: nextReddit => {
dispatch(selectReddit(nextReddit));
}
};
}
export default connect(mapStateToProps, mapDispatchToProps)(App)
Component App will then be empowered with a prop onClick which is used as below.
handleChange = nextReddit => {
this.props.onClick(nextReddit)
}
render() {
...
return (
...
<Picker value={selectedReddit}
onChange={this.handleChange}
options={[ 'reactjs', 'frontend' ]} />
...
);
}

Passing props to react-redux container component

I have a react-redux container component that is created within a React Native Navigator component. I want to be able to pass the navigator as a prop to this container component so that after a button is pressed inside its presentational component, it can push an object onto the navigator stack.
I want to do this without needing to hand write all the boilerplate code that the react-redux container component gives me (and also not miss out on all the optimisations that react-redux would give me here too).
Example container component code:
const mapStateToProps = (state) => {
return {
prop1: state.prop1,
prop2: state.prop2
}
}
const mapDispatchToProps = (dispatch) => {
return {
onSearchPressed: (e) => {
dispatch(submitSearch(navigator)) // This is where I want to use the injected navigator
}
}
}
const SearchViewContainer = connect(
mapStateToProps,
mapDispatchToProps
)(SearchView)
export default SearchViewContainer
And I'd want to be able to call the component like this from within my navigator renderScene function:
<SearchViewContainer navigator={navigator}/>
In the container code above, I'd need to be able to access this passed prop from within the mapDispatchToProps function.
I don't fancy storing the navigator on the redux state object and don't want to pass the prop down to the presentational component.
Is there a way I can pass in a prop to this container component? Alternatively, are there any alternative approaches that I'm overlooking?
Thanks.
mapStateToProps and mapDispatchToProps both take ownProps as the second argument.
[mapStateToProps(state, [ownProps]): stateProps] (Function):
[mapDispatchToProps(dispatch, [ownProps]): dispatchProps] (Object or Function):
For reference
You can pass in a second argument to mapStateToProps(state, ownProps) which will give you access to the props passed into the component in mapStateToProps
There's a few gotchas when doing this with typescript, so here's an example.
One gotcha was when you are only using dispatchToProps (and not mapping any state props), it's important to not omit the state param, (it can be named with an underscore prefix).
Another gotcha was that the ownProps param had to be typed using an interface containing only the passed props - this can be achieved by splitting your props interface into two interfaces, e.g.
interface MyComponentOwnProps {
value: number;
}
interface MyComponentConnectedProps {
someAction: (x: number) => void;
}
export class MyComponent extends React.Component<
MyComponentOwnProps & MyComponentConnectedProps
> {
....// component logic
}
const mapStateToProps = (
_state: AppState,
ownProps: MyComponentOwnProps,
) => ({
value: ownProps.value,
});
const mapDispatchToProps = {
someAction,
};
export default connect(mapStateToProps, mapDispatchToProps)(MyComponent);
The component can be declared by passing the single parameter:
<MyComponent value={event} />
Using Decorators (#)
If you are using decorators, the code below give an example in the case you want to use decorators for your redux connect.
#connect(
(state, ownProps) => {
return {
Foo: ownProps.Foo,
}
}
)
export default class Bar extends React.Component {
If you now check this.props.Foo you will see the prop that was added from where the Bar component was used.
<Bar Foo={'Baz'} />
In this case this.props.Foo will be the string 'Baz'
Hope this clarifies some things.

Resources