MapStateToProps and MapDispatchToProps in React Redux
In this video you will learn such important things to work with Redux is mapStateToProps and mapDispatchToProps.
Let's jump right into it.
So first of all let's talk deeper about mapStateToProps. The main difference with working through react-redux is that we don't have an access to store in every component. We can only get some data in store using mapStateToProps. This is exactly what we did in previous lesson. So we have a store with array of users inside and to get them inside our App component we must use mapStateToProps. There is no other way.
As you see we are getting as a first argument the whole state and can normalize or change data here like we want. But we must return an object. So we can't really return the array of users. We must pack them in object.
Now we can normalize data how we want inside our mapStateToProps function. For example let's say that we want to get an array of users from all our users where name contains foo.
const mapStateToProps = (state) => {
console.log("state", state);
const usersWithFoo = state.filter((user) => user.includes("foo"));
return {
users: state,
usersWithFoo,
};
};
So here we first transformed our state by filtering users and then returned them as a new property. As you can see we are getting this data just like normal props.
The most important part to remember is that there is no magic. We create a function which gets a state as a parameter and define how we want to get data back. Then we throw this function inside connect and every single time when our state changes this function will be called and give us new props back.
But it's not the only goal of mapStateToProps to give us a slice of state. It also implements shouldComponentUpdate comparisons inside. Which means yes it fires every time when state changes but our component props will be changed only when they really change. So our component won't be rerendered on every change of the state. It rerenders only when props of component change.
One more thing that you need to know is that we can also access props that are passed inside component from outside inside mapStateToProps. And this is extremely important if you want to make some calculation based on the Redux state and props. For example we can pass a search text inside props of App component.
index.js
<App searchText="foo" />
Now as you can see in logs we are getting it inside props of our App component. So let's say that we want to get filtered users by this searchValue. For this we have a full access to all own props of the component inside the second parameter.
const mapStateToProps = (state, ownProps) => {
console.log("state", state);
const usersWithFoo = state.filter((user) =>
user.includes(ownProps.searchText)
);
return {
users: state,
usersWithFoo,
};
};
As you can see everything is working exactly like previously but now we are using searchText from props of the component.
Now let's talk about one more function which is mapDispatchToProps. Actually it's not mandatory because as you saw react-redux injects inside props dispatch function and we can dispatch our actions without any problem. But it makes code more readable this is why it is worth to use it. So the main idea is to hide from the component itself that we are dispatching something but just call functions instead. It can also help with testing our component later.
So let's create mapDispatchToProps as a second parameter of connect.
const mapDispatchToProps = (dispatch) => {
return {
addUser: (username) => dispatch({ type: "ADD_USER", payload: username }),
};
};
export default connect(mapStateToProps, mapDispatchToProps)(App);
So we passed as a second parameter mapDispatchToProps. It's a function where we get dispatch as an argument. We must also return here an object. And the idea is that we create here functions which just wrap our dispatch with some data. So here we created addUser function which inside calls dispatch. Now we can use addUser function from props and our component won't know anything about dispatch.
addUser = () => {
console.log("addUser", this.state.username);
this.props.addUser(this.state.username);
};
As you can see it is working exactly like before.
It is also possible to make mapDispatchToProps an object. But for this we must wrap our dispatches in additional function beforehand.
const addUser = (username) => {
return { type: "ADD_USER", payload: username };
};
const mapDispatchToProps = {
addUser,
};
So we created an additional function which return an action. Just to remind you we are calling an object with type and any additional data an "Action". Now we defined mapDispatchToProps not as a function but as an object with key of our function. It will work exactly like before and internally will dispatch an action that we returned.
As you can see it is working as expected.
So the function that returns an action is called "Action creator" and you need to remember that because we will use this term a lot.
One more important thing to remember that you get dispatch in props only if you don't create mapDispatchToProps. At the moment when you create it it won't be available anymore.
One more thing is that you sometimes don't need mapStateToProps and only mapDispatchToProps. You can easily skip it just by providing null as a first argument.
And the last thing that you might think about is that you still have store inside index.js. And it's just a normaly Redux instance. To you might think that you can use directly getState or dispatch from it. And this is the hugest antipattern that you can imagine. You only need to work with Redux through connect function.
And this was everything that you need to know about mapStateToProps and mapDispatchToProps functions.
Want to conquer your next JavaScript interview? Download my FREE PDF - Pass Your JS Interview with Confidence and start preparing for success today!
📚 Source code of what we've done