Accessing props from state using mergeProps
While using Redux, you may come across a situation where you are passing in props from both mapStateToProps
and mapDispatchToProps
, and using them together:
// Button.js const Button = ({ name, setName }) => ( <button onClick={setName(name)}>Click</button> ); const mapStateToProps = (state) => ({ name: getName(state), }); const mapDispatchToProps = (dispatch) => ({ setName: (name) => dispatch(setName(name)), }); export default connect(mapStateToProps, mapDispatchToProps)(Button);
We can save Button
having to know about name
, and instead use mergeProps
:
// Button.js const Button = ({ setName }) => ( <button onClick={setName}>Click</button> ); const mapStateToProps = (state) => ({ name: getName(state), }); const mapDispatchToProps = (dispatch) => ({ setName: (name) => () => dispatch(setName(name)) }); const mergeProps = (stateProps, dispatchProps) => ({ setName: dispatchProps.setName(stateProps.name), }); export default connect(mapStateToProps, mapDispatchToProps, mergeProps)(Button);
What does mergeProps do?
mergeProps
is an optional third argument you can pass into connect
. As the name suggests, it merges all the props into one object for your component to use. By default, it will look like this:
(stateProps, dispatchProps, ownProps) => ({ ...stateProps, ...dispatchProps, ...ownProps })
-
stateProps
are all the props frommapStateToProps
- in the above example,name
-
dispatchProps
are all the props frommapDispatchToProps
-setName
-
ownProps
are all props that are passed into a component like this<Button foo={bar}/>
Accessing ownProps in mapDispatchFromProps
We can also access ownProps
from mapDispatchToProps
. Here we have the same Button
example, but instead of name coming from mapStateToProps
, this time itโs being passed in from the Form
component:
// Form.js import Button from './Button'; const Form = () => ( <> {/* A bunch of other stuff... */} <Button name={'Emma'} /> </> ); // Button.js const Button = ({ name, setName }) => ( <button onClick={setName(name)}>Click</button> ); const mapDispatchToProps = (dispatch) => ({ setName: (name) => dispatch(setName(name)), }); export default connect(null, mapDispatchToProps)(Button);
We can use the name
prop directly in mapDispatchToProps
by using its second argument, ownProps
:
const Button = ({ setName }) => ( <button onClick={setName}>Click</button> ); const mapDispatchToProps = (dispatch, ownProps) => ({ setName: () => dispatch(setName(ownProps.name)), }); export default connect(null, mapDispatchToProps)(Button);
Even if name
is now unused, it will still be passed in as part of ownProps
to the Button
component. We can filter it out using mergeProps
:
const mergeProps = (stateProps, dispatchProps, ownProps) => ({ ...dispatchProps, }); export default connect(null, mapDispatchToProps, mergeProps)(Button);
Pro-tip: Using mapDispatchToPropsโ object form
Youโll notice that I always defined mapDispatchToProps
in its function form:
const mapDispatchToProps = (dispatch) => ({ setName: (name) => dispatch(setName(name)) });
If youโre not making use of ownProps
or mergeProps
, we can actually simplify it down to its object form, which does the exact same thing:
const mapDispatchToProps = { setName, };
Thanks for reading!
Top comments (0)