redux pre-binding through bindActionCreators, an anti-pattern? - reactjs

Throughout my redux App, I frequently finding myself using the following pattern
// declare an action creator in a centralized / state management related location in the App (i.e. not the components/containers)
const myActionCreator1 = () => (dispatch) => { ... }
const myActionCreator2 = createAction(ACTION_2)
// then later in a mapDispatchToProps of a Container component
function mapDispatchToProps(dispatch) {
bindActionCreators({myActionCreator1, myActionCreator2}, dispatch);
}
Is these cases, is it an anti-pattern to pre-bind the action creators? given that there is only 1 dispatcher in redux working against 1 store?
i.e.
// actionCreators.ts
export const myActionCreators = {
myActionCreator: bindActionCreators(..., dispatch)
}
If this is pattern has no downside that would be good news for conciseness ....
Clarification
the conciseness benefit will only be apparent when multiple components re-use the same action creator. As these components will no longer require a mapDispatchToProps for straight-forward cases like the examples above

The connect function supports an "object shorthand" syntax for the second argument. Instead of creating a mapDispatchToProps function that receives dispatch (and probably uses bindActionCreators inside), you can just pass an object full of action creators directly to connect:
const actionCreators = {
addTodo,
toggleTodo
};
export default connect(null, actionCreators)(MyComponent);
That object full of action creators will be automatically run through bindActionCreators, and calling this.props.addTodo("Buy Milk") will dispatch the action creator appropriately.
I discussed some of the advantages of this approach in my blog post Idiomatic Redux: Why use action creators?.

Related

Redux toolkit: Exporting a custom hook from slice file to access actions instead of exporting all actions and then calling it again with dispatch?

Inside a slice file we export all the the actions from that slice. For example:
export const {signoutUser, updateProfile, authenticateUser, clearUserState} = sliceName.actions;
And then we import useDispatch and particular actions from the slice or action file based on your folder structure. For example
import {clearUserState} from './slice';
import { useDispatch } from 'react-redux';
export const Component () {
const dispatch = useDispatch(clearUserState());
//rest component body
}
Now instead I am exporting a custom hook from the slice file like mentioned below:
export const useUserDispatch = () => {
const dispatch = useDispatch();
const userDispatch = {
signoutUser: (data) => dispatch(signoutUser(data)),
updateProfile: (data) => dispatch(updateProfile(data)),
authenticateUser: (data) => dispatch(authenticateUser(data)),
clearUserState: () => dispatch(clearUserState())
};
return {userDispatch}
};
And then i can just import that hook and use like
const {userDispatch}=useUserDispatch();
//inside component
<button onClick={userDispatch.clearUserState()}>Dispatch Button</button>
I just wanted to know if it's something that's not recommended in terms of redux way of writing code or am I doing anything wrong, it works perfectly fine though.
There is nothing wrong with your code. and the question can not be answered to pros and cons based on my experience, redux and all other open-source packages consider base common cases which people are using in the everyday app. There might be some suggestions for improvement but not best-case explanations for every app. you can just consider following and decide yourself
You can not use them as you mentioned useUserDispatch().clearUserState()
e.g.
<button onCleack={useDispatcher().clearUserState}>clear</button>
Hooks can be called conditionally so calling them as this level in the UI part might be conditionally canceled which is a really common case
every time this hook is called a hole new object is created for dispatchers
Also, useDispatch doesn't receive any argument and returns the nearest redux provider store.dispatch. see source code
Note: Redux suggests having one state for all of your apps and doesn't wrap part of your code with multiple providers.
Remember if you need this one of dispatcher (e.g. updateProfile) from some other part of the code, you may need to use this hook which is a waste of resources, or use it directly which shows a is a little bit of uncertainty and be not consistent from the other version (just a little is not a big case).
There are other options to handle these cases.
Remember what redux suggests for one provider, if you accept that you can also write your own dispatcher.
const storeDispatch = store.dispatch
// from slice file export dispatcher instead of action creator
const updateProfile = sliceName.actions.updateProfile;
export const updateProfileDispatcher = (data) => storeDispatch(updateProfile(data))
This can not only be used in your component but also can be used outside of react component inside the logic
Note: using a dispatcher outside the react is not the standard or recommended pattern and you might not want to use it.
You can also pass dispatch as the argument, something like thunk dispatcher
const updateProfile = dispatch => (data) => dispatch(updateProfile(data))
// or alongside of payload data
const updateProfile = (dispatch, data) => dispatch(updateProfile(data))
// also can set the default value of dispatch to store.dis
const updateProfile = (data, dispatch=storeDispatch) => dispatch(updateProfile(data))
// component
const dispatch = useDispatch()
<ProfileComponent onUpdate={updateProfile(dispatch)} />

Passing mapDispatchToProps as an object or a function to connect have the same outcome

I'm beginner, learning React with Redux, I came across a situation where,
These two code samples lead to the same result:
case 1: without using dispatch
export default connect(mapStateToProps,
{
getContacts : () => {
return {
type:GET_CONTACTS
}
}
}
)(Contacts);
case 2: using dispatch
export default connect(mapStateToProps,
dispatch => ({
getContacts : () => {
return dispatch({type:GET_CONTACTS})
}
})
)(Contacts);
Can someone explain me why does these two code examples work in the same way?
And why we don't need to use dispatch in case 1?
Both would result the same. There are two ways to define mapDispatchToProps.
Function form: Allows more customization, gains access to dispatch and optionally ownProps.
Object shorthand form: More declarative and easier to use.
Why to do dispatch instead of calling function normally?
In redux the store is single source of truth, the dispatch you are using is actually comes from store (store.dispatch).
If you call a function normally then it won't be aware by the store. That action won't pass through the middlewares (thunk/saga) that store is aware of and won't do perform store update via reducers.
If store is not updated, your connected components won't receive any updates. Eventually your UI won't re-render.

What is going on in this Redux code...confused about mapDispatchToProps, dispatch, and connect

I'm following a react tutorial and I had a few questions.
I am confused about this function:
function mapDispatchToProps(dispatch) {
return bindActionCreators({ fetchWeather }, dispatch)
}
I want to breakdown each part of this function.
How do you hook up the action creator to a container? How is this.props.fetchWeather working code? Is this responsible for that?:
function mapDispatchToProps(dispatch) {
If so, what is this doing?
return bindActionCreators({ fetchWeather }, dispatch)
Is that responsible for making sure that the action object that is returned from the action creator flows down into the middleware and reducers?
What is this doing then:
function mapDispatchToProps(dispatch)
Is mapDispatchToProps just convention or is it part of react?
Lastly, what is this export doing:
export default connect(null, mapDispatchToProps)(SearchBar);
What is the connect doing? What does it do for me?
Here is my whole code for reference:
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';
import { fetchWeather } from '../actions/index';
class SearchBar extends Component {
constructor(props) {
super(props);
this.state = { term: '' };
this.onInputChange = this.onInputChange.bind(this);
this.onFormSubmit = this.onFormSubmit.bind(this);
}
onInputChange(event) {
this.setState({ term: event.target.value });
}
onFormSubmit(event) {
event.preventDefault();
this.props.fetchWeather(this.state.term);
this.setState({ term: '' });
}
render() {
return (
<form onSubmit={this.onFormSubmit} className="input-group">
<input
placeholder="Get a five-day forecast in your favorite cities"
className="form-control"
value={this.state.term}
onChange={this.onInputChange}
/>
<span className='input-group-btn'>
<button type="submit" className="btn btn-secondary">
Submit
</button>
</span>
</form>
);
}
}
function mapDispatchToProps(dispatch) {
return bindActionCreators({ fetchWeather }, dispatch)
}
export default connect(null, mapDispatchToProps)(SearchBar);
A very concise answer would be:
mapStateToProps() is a utility which helps your component gets updated state(which is updated by some other components)
mapDispatchToProps() is a utility which will help your component to fire an action event (dispatching action which may cause a change of application state)
bindActionCreators() is mostly used when you want to pass some action creators down to a component that isn't aware of Redux, and you don't want to pass dispatch or the Redux store to it.
<Provider> makes the Redux store available to the your "connected" React components.
connect() is a higher-order component (HOC) that lets you inject Redux state into a regular React component.
Let's dive a bit deeper
ReactJS - JS library for building user interfaces.
Redux - JS library for managing application state.
Putting them together using react-redux:
If we want to link our React application with the Redux store, we first have to let our app know that this store exists. This is where we come to the first major part of the react-redux library, which is the Provider.
A Provider is a React component given to us by the react-redux library. It serves just one purpose: to “provide” the store to its child components.
Provider
Makes the Redux store available to the connect() calls in the component hierarchy below. Normally, you can’t use connect() without wrapping a parent or ancestor component in <Provider>. So ultimately connect does just that, it connects your React app to the Redux store.
//This is the store we create with redux's createStore method
const store = createStore(todoApp, {})
// Provider is given the store as a prop
render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById('app-node')
)
Props
store (Redux Store): The single Redux store in your application.
children (React Element): The root of your component hierarchy.
Explanation and usage of the Connect function:
Now that we have “provided” the redux store to our application, we can now connect our components to it. We established previously that there is no way to directly interact with the store. We can either retrieve data by obtaining its current state or change its state by dispatching an action (we only have access to the top and bottom component of the redux flow diagram shown previously). This is precisely what connect() does.
To use connect(), you need to define a special function called mapStateToProps that describes how to transform the current Redux store state into the props you want to pass to a presentational component you are wrapping.
In addition to reading the state, container components can dispatch actions. In a similar fashion, you can define a function called mapDispatchToProps() that receives the dispatch() method and returns callback props that you want to inject into the presentational component.
Simple explanation and a basic example of mapStateToProps
The Store is a box, which contains the entire application state. Imagine that this box is in an unknown location.
The components need to take some of the things out of the box but they only need some of the things stored in it. The components know what they need from the box but they don't know where the box is.
The mapStateToProps function is a filter used to select which things in the box are required by the component. The selected things become the component properties.
The mapStateToProps function is not enough because it selects the required things in the box but it doesn't know where the box is located.
The connect function knows where the box is located and passes it to the mapStateToProps function so it can grab what it needs.
Conclusion: mapStateToProps simply returns a specified part of the current state. mapStateToProps get the data that is fed to its component.
const mapStateToProps = (state) => {
return { things: state.things }
};
So now we're able to use that part of the state as props -> this.props.things
But what if the component wants to change the state? That is where mapDispatchToProps comes in.
Simple explanation and a basic example of mapDispatchToProps
As implied in its name, this function directs the dispatching or sending of an action by pointing it to an action creator. For example:
const mapDispatchToProps = () => {
return {
addThing: addThing,
doAnotherThing: doAnotherThing
}
}
mapDispatchToProps takes the dispatch functions in your component and executes them against the Redux reducer when that function is fired. Remember that Props aren’t just objects, they can also be functions. This is where mapDispatchtoProps applies. MapDispatchToProps allows for you to dispatch state changes to your store. An example would be a button click that triggers a refresh or an automatic loading of data once the component is mounted.
The action creator is made available to the component as a prop, which is usually tied to an event handler function contained in the component:
handleOnClick() {
this.props.addThing();
};
However, returning the action creator is only one part. We also want the send that returned action to the store. How do we do that? We use Redux’s bindActionCreators().
Simple explanation and a basic implementation of bindActionCreators():
Turns an object whose values are action creators, into an object with the same keys, but with every action creator wrapped into a dispatch call so they may be invoked directly.
Normally you should just call dispatch directly on your Store instance. If you use Redux with React, react-redux will provide you with the dispatch function so you can call it directly, too.
The only use case for bindActionCreators is when you want to pass some action creators down to a component that isn't aware of Redux, and you don't want to pass dispatch or the Redux store to it.
To implement it, we:
import { bindActionCreators } from 'redux';
...
const mapDispatchToProps = (dispatch) => {
return bindActionCreators({
addThing: addThing,
doAnotherThing: doAnotherThing
}, dispatch);
};
The bindActionCreators() function accepts the action creator and the store’s dispatch function as arguments, and returns a dispatch function that uses the return value of the action creator as its arguments.
Once again, tying this all together is the connect() function, in which we pass mapDispatchToProps as a second argument. For example:
export default connect(mapStateToProps, mapDispatchToProps)(MyComponent);
which will export a component that can both get the current state from the store, and dispatch an action to the store to trigger and update to the state.
Now, let's put it all together with a little TodoItem.js React functional component:
import { connect } from 'react-redux'
const TodoItem = ({ todo, destroyTodo }) => {
return (
<div>
{todo.text}
<span onClick={destroyTodo}> x </span>
</div>
)
}
const mapStateToProps = state => {
return {
todo: state.todos[0]
}
}
const mapDispatchToProps = dispatch => {
return {
destroyTodo: () =>
dispatch({
type: 'DESTROY_TODO'
})
}
}
export default connect(
mapStateToProps,
mapDispatchToProps
)(TodoItem)
mapStateToProps and mapDispatchToProps are both pure functions that are provided the stores “state” and “dispatch” respectively. Furthermore, both functions have to return an object, whose keys will then be passed on as the props of the component they are connected to.
In this case, mapStateToProps returns an object with only one key: “todo”, and mapDispatchToProps returns an object with the destroyTodo key.
The exported connected component provides todo and destroyTodo as props to TodoItem functional component

Dispatch in react redux

I am new to react and redux xo my questions will sound basic.
What does dispatch means? I am referring to the term dispatching an action.
Why do we need mapDispatchToProps to store actions on redux? We can simply import an action and use it. I have a scenario in which I have to load data when a component is mounted.
#mariazahid mapDispatchToProps will bind the action to your component so that you can pass it down to your presentation components. This is a pattern that is normally used within using Redux with React.
You can import your action and just dispatch the action, but in most scenarios a container -> component pattern is used. A container is where the actions are mapped to and the state and the only goal of this component is to pass this data down to components that are used for presenting that data.
When working in teams, it's a pattern that is easily adoptable. Instead of importing actions from left right and center, you will just have to be aware of the container and how it passes the required actions/data down to the children.
From an implementation perspective, dispatch is just a method that is used to communicate with your reducers
Let say that your action looks something like this
function myAction() {
return { type: 'MY_ACTION' };
}
You're trying to communicate with the reducer that responds to the action type 'MY_ACTION'
In your mapDispatchToProps you'd typically do something like this;
function mapDispatchToProps(dispatch) {
return { actions: bindActionCreators(myActions, dispatch) }
}
Effectively, you're wrapping(binding) your actions to the dispatch method;
function bindActionCreators(actions, dispatch) {
// this is a very trivial implementation of what bindActionCreators does
let wrappedActions = {};
Object.keys(actions).forEach(action =>
// for every action, return a function that calls dispatch on the result of what your action returns
return function(...args) {
// remember here that dispatch is the only way you can communicate with the reducers and you're action's type will determine which reducer responds to return the new state
return dispatch(actions[action](..args));
}
);
}
And so, these "bound" actions are now assigned to a props.actions in your component.

when is mapDispatchToProps function used

I have come across this piece of code while learning react-redux
export const mapDispatchToProps = (dispatch, getState) => {
return ActionCreators({completeDriver}, dispatch, getState);
};
I want to know when to use this function.
as per redux actions are dispatched like dispatch(actionCreator())
for doing so inside an react component you need the reference of dispatch which need to be passed as prop to your component.
so if you use connect() you can reduce this passing of dispatch as prop by yourself this thing will be handed via connect HOC(Higher Order Component).
for larger scale application using mapDispatchToProps of connect would saves lot of dev time of wiring things.

Resources