Purpose of mapDispatchToProps in Redux land - reactjs

Is there a purpose to mapDispatchToProps:
const mapDispatchToProps = dispatch => {
return {
addProductToCart: product => dispatch(addProductToCart(product))
}
}
or is it acceptable to just do this:
const mapDispatchToProps = dispatch => {
return {dispatch};
}
and then just call:
props.dispatch() in the component

mapDispatchToProps allows you to simply specify actions your component needs to dispatch. You may take this approach because it's more declarative (letting the mapDispatchToProps handle all the heavy lifting so you can easily call a function from your component) or perhaps you want to share the dispatch function with an unconnected redux component.
In fact, it is perfectly acceptable not to have a mapDispatchToProps function at all.
Additionally based on your example. Instead of doing the following:
const mapDispatchToProps = dispatch => {
return {dispatch};
}
You could simply exclude the mapDispatchToProps function from the connect method like so:
connect(mapStateToProps)(MyComponent)
Then do the following in your component:
props.dispatch({ type: 'MY_ACTION' })}

Without mapDispatchToProps:-
this.props.dispatch(showAlert(message));
With mapDispatchToProps:-
this.props.onShowAlert(message);
THis was the main perpose of mapDispatchToProps

Related

In React / Redux, is it just fine to make a generic dispatch as props to dispatch any action at all?

In one of Dan Abramov's answers, there is code
// action creator
function loadData(dispatch, userId) { // needs to dispatch, so it is first argument
return fetch(`http://data.com/${userId}`)
.then(res => res.json())
.then(
data => dispatch({ type: 'LOAD_DATA_SUCCESS', data }),
err => dispatch({ type: 'LOAD_DATA_FAILURE', err })
);
}
// component
componentWillMount() {
loadData(this.props.dispatch, this.props.userId); // don't forget to pass dispatch
}
It seems the mapDispatchToProps just maps a generic dispatch as props (as this.props.dispatch), so this component can dispatch any action at all?
First, is it a good form, or is it just an example but we should make it specific dispatch, such as this.props.dataReceived?
Second, so it looks like for the above code, the mapDispatchToProps would be written as:
const mapDispatchToProps = dispatchOfReduxStore => {
return {
dispatch: dispatchOfReduxStore
}
}
or even just:
const mapDispatchToProps = dispatch => {
return {
dispatch
}
}
and simplified to:
const mapDispatchToProps = dispatch => ({ dispatch })
and this.props.dispatch becomes a versatile dispatch?
I also found that when we simply omit the mapDispatchToProps in connect(), then this.props.dispatch is automatically available.
I think the main reason for binding dispatch to your actions with mapDispatchToProps is to hide redux from your connected component.
Without binding dispatch, your component must know what your actions are and remember that they do nothing without calling them as a parameter to dispatch.
With binding, your component just knows that it has these functions in props that it can simply call when needed.
The other benefit would be arguably cleaner code, since you can just call this.props.myAction() instead of this.props.dispatch(myAction()).
I don't think its a hard right or wrong. I think some of it is preference. I prefer to write my components to where they only know about the props given to them. But you may prefer to make it explicit that your component is using redux to dispatch actions.

How to call reducer action without redux saga

I have redux saga in my project, but I would like to call reducer action directly from my component.
const mapDispatchToProps = (dispatch) => ({
showUsers: () => dispatch(UserActions.showUsers()),
})
It works fine if showUsers is inside saga
mapDispatchToProps can be a simple object with the action inside
const mapDispatchToProps = {
showUsers: UserActions.showUsers,
};
then you can pass it to connect. connect will call dispatch internally
connect(null, mapDispatchToProps)(MyComponent)
then inside your component, you can call your action
this.props.showUsers()
More info about the different forms of mapDispatchToProps

How to correctly type action creators mapped to props in react-redux

In our project all action creators are defined like this:
export const actionCreatorFunctionName(arg1, arg2...) {
return (dispatch: Dispatch, getStore: () => StoreState) => {
// ... function logic ...
dispatch(actionFunctionName(args...));
}
}
Some of the action creators make HTTP requests and don't call dispatch before the request is resolved.
These action creators are mapped to props using the connect hoc like this:
import * as ActionCreators from "./actionCreators";
connect(mapStateToProps, { actions: ActionCreators })(SomeComponent);
The issue is that it seems to be impossible to configure the props interface for the component correctly when using this setup. We have tried configuring Props like this:
interface Props {
actions: typeof ActionCreators;
}
But this does not work, because the actions prop is not really the same type as ActionCreators because the connect hoc changes the actionCreators from functions that returns functions to plain functions.
I think in addition to defining the actions, you will want to define an Actions type that you can export and use in your props.
export type Actions = {
action1: (arg1: string) => void,
action2: (arg1: string, arg2: number) => void
}
export function action1(arg1: string) {
// ...
}
And then use the Actions interface in your props
type Props = {
actions: Actions
}
If I understand correctly, you are having trouble sending state from the store to the Component?
If that is the case, let's assume you have data in your store for an object called items, put the below code above your connect statement in the Component (this makes the items data available to your Component);
const mapStateToProps = (state) => {
items: state.items
}

MapDispatchToProps doesn't work on returning an object

If I make my own mapDispatchToProps function, it doesn't work. If I give a plain object for connect then it does work, but I need the dispatch functionality.. for eg loading of translations per page, Am I doing something wrong here?
const mapStateToProps = (state) => {
const { isFetching, lastUpdated, items, errors } = state.transactions; // fetch from redux state ;)
return {
translate: getTranslate(state.locale),
isFetching,
lastUpdated,
items,
errors
}
}
const mapDispatchToProps = dispatch => {
return {
fetchTransactionsIfNeeded,
invalidateList
}
}
export default connect(mapStateToProps, mapDispatchToProps)(Transactions);
The code below works
const mapStateToProps = (state) => {
const { isFetching, lastUpdated, items, errors } = state.transactions; // fetch from redux state ;)
return {
translate: getTranslate(state.locale),
isFetching,
lastUpdated,
items,
errors
}
}
export default connect(mapStateToProps, {
fetchTransactionsIfNeeded,
invalidateList
})(Transactions);
According to the redux documentation
[mapDispatchToProps(dispatch, [ownProps]): dispatchProps] (Object or Function): If an object is passed, each function inside it is
assumed to be a Redux action creator. An object with the same function
names, but with every action creator wrapped into a dispatch call so
they may be invoked directly, will be merged into the component’s
props.
If a function is passed, it will be given dispatch as the first
parameter. It’s up to you to return an object that somehow uses
dispatch to bind action creators in your own way. (Tip: you may use
the bindActionCreators() helper from Redux.)
In first case when you implement mapDispatchToProps, you are returning a plain object, but you need to use dispatch in it, since its not assumed as an action creator by itself by redux.
You would implement it like
const mapDispatchToProps = dispatch => {
return {
fetchTransactionsIfNeeded: (...args) => {
dispatch(fetchTransactionsIfNeeded(...args))
},
invalidateList: (...args) => {
dispatch(invalidateList(...args))
},
}
}
or else don't create it as a function but simply an object
const mapDispatchToProps = {
fetchTransactionsIfNeeded,
invalidateList
}

mapDispatchToProps: any point?

I was wondering if there was still a point using mapDispatchToProps today.
I'm working on the redux documentation tutorials (to build a todo list) where VisibleTodoList is described as:
import { connect } from 'react-redux'
import { toggleTodo } from '../actions'
import TodoList from '../components/TodoList'
const getVisibleTodos = (todos, filter) => {
switch (filter) {
case 'SHOW_ALL':
return todos
case 'SHOW_COMPLETED':
return todos.filter(t => t.completed)
case 'SHOW_ACTIVE':
return todos.filter(t => !t.completed)
}
}
const mapStateToProps = (state) => {
return {
todos: getVisibleTodos(state.todos, state.visibilityFilter)
}
}
const mapDispatchToProps = (dispatch) => {
return {
onTodoClick: (id) => {
dispatch(toggleTodo(id))
}
}
}
const VisibleTodoList = connect(
mapStateToProps,
mapDispatchToProps
)(TodoList)
export default VisibleTodoList
However, I've been told that today, I could simply not to define mapDispatchToProps and connect everything through:
const VisibleTodoList = connect(
mapStateToProps,
toggleTodo
)(TodoList)
Is it right? And if so, what is the point to write a mapDispatchToProps? Is there any drawbacks to simply returning the action?
Thanks!
To clarify the other Mark's comment:
The second argument to connect() can take two main forms. If you pass a function as the argument, connect() assumes you want to handle dispatch preparation yourself, calls your function with dispatch as an argument, and merges the result into the props for your component.
If you pass in an object as the second argument to connect(), it assumes you've given it a map of prop names to action creators, and so it automatically runs all of them through the bindActionCreators utility and uses the result as props.
However, passing a single action creator as the second argument, as your example appears to do, would not do what you want, as connect() would interpret that as a preparation function and not an action creator that needs to be bound.
So yes, connect() supports a shorthand syntax of passing in an object full of action creators as the second argument, but there are still good use cases for passing in an actual mapDispatchToProps function to do things yourself (especially if your dispatch prep relies on the actual prop values in some way).
You might want to refer to the API docs for `connect().
connect() will automatically bind dispatch to your actions if they are passed in as an object of function names.
So no, you don't need to implement mapStateToProps. Instead you can just pass you actions like this:
export default connect((state) => state, {
action1,
action2,
})(MyComponent);

Resources