Why I'll definitely use mapDispatchToProps in Redux
January 05, 2020 - 4 minutes
Not too uncommon, at my job we make use of Redux in our React frontend stack for state management. A lot of components are connected to the store using Redux’s connect
and retrieve data from it through mapStateToProps
using selectors. Components also need to interact with the store through actions or thunks, which is possible with the dispatch
function that connect
injects. With those concepts in mind, I’ve passed along the dispatch
function to the component and used it inside its callbacks and lifecycle methods for quite some time now, without ever second guessing this approach. Until recently that is, when I learned about the second argument of the connect
function: mapDispatchToProps
.
What is mapDispatchToProps
?
In short, mapDispatchToProps
is a function that maps the dispatch
function and returns an object of functions, which will be merged into the existing props and made available to your component as additional ones. It’s very similar to mapStateToProps
, which maps the state to props for your component, but then for the dispatch
function and the values of the return object have to be functions. If you want to learn more about what mapDispatchToProps
is and how to use it, you should read the Redux docs as they explain it in quite some detail.
function mapDispatchToProps(dispatch) {
return {
doSomething: () => {
dispatch(somethingDispatchable());
},
};
}
class SomeComponent extends React.Component {
componentDidMount() {
// Instead of `this.props.dispatch(somethingDispatchable());`
this.props.doSomething();
}
// or...
render() {
const { doSomething, ...otherProps } = this.props;
return <button onClick={doSomething} />;
}
}
export const SomeConnectedComponent = connect(null, mapDispatchToProps)(SomeComponent);
Why use mapDispatchToProps
?
First of all, it shares a lot of benefits with mapStateToProps
, like making your code more declarative and making sure that Redux related code is more grouped together. The latter might not seem so impactful for mapStateToProps
, as it’s only responsible for retrieving data from the store. But in the case of mapDispatchToProps
, it’s definitely something not to overlook as it’s responsible for defining the logic of the component’s interactions with the store. Logic code has always been difficult to maintain, and keeping related logic together is one way of making this process easier. A concrete example is the introduction of Hooks in React.
It also reduces boilerplate code in your components as less callbacks are required in which dispatch
is called and the logic is moved somewhere else. This in turn reduces how bloated your components are, thus resulting into components that are easier to read and maintain. This is especially the case for class components, which are more verbose in general.
However, the main benefit that I see in using mapDispatchToProps
is the separation it creates between store related logic and the view of the component and the testing benefits that come with it. Components are not aware anymore of dispatch
and thus don’t need to know how things have to be done anymore. Rather, all the logic is abstracted away. Which means that the components only see the resulting props and only need to bother with what they do and when to use them. This significantly increases the reusability and testability of the component.
While it’s up for debate whether components should be tested with or without the store, there are use cases in which you need the unconnected component or where it makes more sense to test the component without an attached store. In those cases, having mapDispatchToProps
means you can more properly and easily test the logic. Rather than mocking the dispatch
function and then verifying whether it’s called with the appropriate action creator/thunk, in which case you’re actually testing implementation details, you can now mock the logic and inject it directly into the component as dependencies.
// Example of how `mapDispatchToProps` makes testing more straightforward.
test('SomeComponent should do something correctly', () => {
const mockedDoSomething = jest.fn();
const component = mount(<SomeComponent doSomething={mockedDoSomething} />);
// Interact with the component to trigger the callback. In this case it's done on mount,
// but here you would simulate click events if it's attached to a button for example.
expect(mockedDoSomething).toHaveBeenCalled();
// Other verifications.
});
Just like the React community, my testing focus is shifting towards verifying behaviour/interactions of my React code, which I’ve also advocated for to do so at my job. Good practices that allow me to write more proper and meaningful tests in an easier way for my React component have interested me a lot since then. The mapDispatchToProps
is a great example of this as it clearly separates Redux related code, the logic, from the React component code, the view. Ultimately, this leads to more reusable and testable components, which is one of the core values of React.