How to get simple dispatch from this.props using connect w/ Redux?
I've got a simple React component that I connect up (mapping a simple array/state over). To keep from referencing the context for store I'd like a way to get "dispatch" directly from props. I've seen others using this approach but don't have access to this for some reason :)
Here are the versions of each npm dependency I'm using currently
"react": "0.14.3",
"react-redux": "^4.0.0",
"react-router": "1.0.1",
"redux": "^3.0.4",
"redux-thunk": "^1.0.2"
Here is the component w/ connect method
class Users extends React.Component {
render() {
const { people } = this.props;
return (
<div>
<div>{this.props.children}</div>
<button onClick={() => { this.props.dispatch({type: ActionTypes.ADD_USER, id: 4}); }}>Add User</button>
</div>
);
}
};
function mapStateToProps(state) {
return { people: state.people };
}
export default connect(mapStateToProps, {
fetchUsers
})(Users);
If you need to see the reducer (nothing exciting but here it is)
const initialState = {
people: []
};
export default function(state=initialState, action) {
if (action.type === ActionTypes.ADD_USER) {
let newPeople = state.people.concat([{id: action.id, name: 'wat'}]);
return {people: newPeople};
}
return state;
};
If you need to see how my router is configured w/ redux
const createStoreWithMiddleware = applyMiddleware(
thunk
)(createStore);
const store = createStoreWithMiddleware(reducers);
var Route = (
<Provider store={store}>
<Router history={createBrowserHistory()}>
{Routes}
</Router>
</Provider>
);
update
looks like if I omit my own dispatch in the connect (currently above I'm showing fetchUsers), I'd get dispatch free (just not sure if this is how a setup w/ async actions would work usually). Do people mix and match or is it all or nothing?
[mapDispatchToProps]
Answer
By default mapDispatchToProps
is just dispatch => ({ dispatch })
.
So if you don't specify the second argument to connect()
, you'll get dispatch
injected as a prop in your component.
If you pass a custom function to mapDispatchToProps
, you can do anything with the function.
A few examples:
// inject onClick
function mapDispatchToProps(dispatch) {
return {
onClick: () => dispatch(increment())
};
}
// inject onClick *and* dispatch
function mapDispatchToProps(dispatch) {
return {
dispatch,
onClick: () => dispatch(increment())
};
}
To save you some typing Redux provides bindActionCreators()
that lets you turn this:
// injects onPlusClick, onMinusClick
function mapDispatchToProps(dispatch) {
return {
onPlusClick: () => dispatch(increment()),
onMinusClick: () => dispatch(decrement())
};
}
into this:
import { bindActionCreators } from 'redux';
// injects onPlusClick, onMinusClick
function mapDispatchToProps(dispatch) {
return bindActionCreators({
onPlusClick: increment,
onMinusClick: decrement
}, dispatch);
}
or even shorter when prop names match action creator names:
// injects increment and decrement
function mapDispatchToProps(dispatch) {
return bindActionCreators({ increment, decrement }, dispatch);
}
If you'd like you can definitely add dispatch
there by hand:
// injects increment, decrement, and dispatch itself
function mapDispatchToProps(dispatch) {
return {
...bindActionCreators({ increment, decrement }), // es7 spread syntax
dispatch
};
}
There's no official advise on whether you should do this or not. connect()
usually serves as the boundary between Redux-aware and Redux-unaware components. This is why we usually feel that it doesn't make sense to inject both bound action creators and dispatch
. But if you feel like you need to do this, feel free to.
Finally, the pattern you are using right now is a shortcut that's even shorter than calling bindActionCreators
. When all you do is return bindActionCreators
, you can omit the call so instead of doing this:
// injects increment and decrement
function mapDispatchToProps(dispatch) {
return bindActionCreators({ increment, decrement }, dispatch);
}
export default connect(
mapStateToProps,
mapDispatchToProps
)(App);
can be written as this
export default connect(
mapStateToProps,
{ increment, decrement } // injects increment and decrement
)(App);
However you'll have to give up that nice short syntax whenever you want something more custom, like passing dispatch
as well.
Related Questions
- → How to update data attribute on Ajax complete
- → October CMS - Radio Button Ajax Click Twice in a Row Causes Content to disappear
- → Octobercms Component Unique id (Twig & Javascript)
- → Passing a JS var from AJAX response to Twig
- → Laravel {!! Form::open() !!} doesn't work within AngularJS
- → DropzoneJS & Laravel - Output form validation errors
- → Import statement and Babel
- → Uncaught TypeError: Cannot read property '__SECRET_DOM_DO_NOT_USE_OR_YOU_WILL_BE_FIRED' of undefined
- → React-router: Passing props to children
- → ListView.DataSource looping data for React Native
- → Can't test submit handler in React component
- → React + Flux - How to avoid global variable
- → Webpack, React & Babel, not rendering DOM