I wanted to know if there is a reason why async actions are like currying functions instead of an arrow function with two parameters
const asyncAction = () => dispatch => {
Thank you!
It's not exactly curried. The important part is that a function is passed into dispatch, like this:
const thunkFunction = (dispatch, getState) => {
// do useful stuff with dispatch and getState
};
store.dispatch(thunkFunction);
But, to be consistent with the rest of good Redux code structure, we use "action creator" functions to encapsulate the process of creating whatever it is we are going to pass to dispatch:
const thunkFunction = someThunkActionCreator(a, b, c);
store.dispatch(thunkFunction);
That way, when we use this in a component, it doesn't even know that there's anything special about the prop function that it's calling:
this.props.someThunkActionCreator(a, b, c);
Related
In my react project I have an actions file that looks like this:
const startLoad = () => async (dispatch) => {
dispatch({
type: CONTENT_LOAD,
});
};
// Get all content
export const getContents = () => async (dispatch) => {
dispatch(startLoad());
// some more code...
};
So in this example, I know that dispatch is coming from the middleware and getContents has access to it because it was mapped using mapDispatchToProps. So I am assuming when getContents is called, its really called like this -> dispatch(getContents) but can this be replicated in plain JavaScript so I can see what is really going on? If I am wrong about why getContents has access to dispatch please let me know.
For example, how isstartLoad able to use dispatch just because dispatch called startLoad? I have noticed that it will also work if I call it like this: dispatch(startLoad(dispatch));.
Passing dispatch in to startLoad actually makes more sense to me so I don't get why that isn't required.
Edit: this is the closest example I could come up with on my own.
const fun = () => (fun2) => {
fun2();
}
const fun2 = () => {
console.log('hello');
}
fun()(fun2);
So I am assuming when getContents is called, its really called like
this -> dispatch(getContents) but can this be replicated in plain
JavaScript so I can see what is really going on? If I am wrong about
why getContents has access to dispatch please let me know.
redux-thunk has quite simple implementation
function createThunkMiddleware(extraArgument) {
return ({ dispatch, getState }) => (next) => (action) => {
if (typeof action === 'function') {
return action(dispatch, getState, extraArgument);
}
return next(action);
};
}
As you can see it checks if action is a function.
And bonus, if you like you can get the whole state and extra argument in params following dispatch
For example, how isstartLoad able to use dispatch just because
dispatch called startLoad? I have noticed that it will also work if I
call it like this: dispatch(startLoad(dispatch));.
It looks like middleware also handles above case.
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.
The code below comes from a Udemy course on the MERN stack by Brad Traversy. I'm new to Redux and Redux Thunk and am trying to understand what the purpose of => dispatch => is. I know it comes from Redux Thunk, which was set up in the Redux store file. I think dispatch is being used here in order to dispatch more than one action from this function and read that the = ([arg(s)]) => dispatch => syntax is an example of currying (though that doesn't seem right since with currying each function has one argument).
I'd greatly appreciate any help understanding => dispatch =>.
(Other minor point of confusion: In the course the function setAlert is referred to as an action, but I'm not sure that's correct since it contains multiple dispatches of actions.)
export const setAlert = (msg, alertType, timeout = 5000) => dispatch => {
const id = uuidv4();
dispatch({
type: SET_ALERT,
payload: { msg, alertType, id }
});
setTimeout(() => dispatch({ type: REMOVE_ALERT, payload: id }), timeout);
};
There's a couple of things going on here:
1) setAlert is what is usually called an "action creator". It's a function that returns an action that you can dispatch later.
2) Redux-Thunk is allowing you to use functions of the form (dispatch) => {} as actions (in place of the more normal object form { type, payload })
It might help if you look at them individually before seeing how they combine together:
// This is an action creator (a function that returns an action)
// This doesn't use redux thunk, the action is just a simple object.
// Because it's an action creator you can pass in arguments
// Because it's not a thunk you can't control when then dispatch happens
const setAlertActionCreator = (msg, alertType) => {
const id = uuidv4();
return {
type: SET_ALERT,
payload: { msg, alertType, id }
};
};
// You use this as:
dispatch(setAlertActionCreator("msg", "type"));
// This is not an action creator it's just an action.
// This IS a redux-thunk action (it's a (dispatch) => {} function not a simple object)
// Because it's not an action creator you can't pass in arguments to get a custom action back
// Because it IS a redux-thunk action you can dispatch more actions later
const setAlertThunk = (dispatch) => {
setTimeout(() => dispatch({
type: SET_ALERT,
payload: {
message: "fixed message",
alertType: "fixed alertType",
id: "fixed id",
}
}), 5000);
};
// You use this as:
dispatch(setAlertThunk);
// When you combine both patterns you gain the ability
// to both pass in arguments and to create additional dispatches
// as the function runs (in this case dispatching again after a timeout.)
// I won't repeat your code, but will show how you would call it:
dispatch(setAlertActionCreator("msg", "type"));
// ie: you use it the same way as example 1.
The syntax () => dispatch => is equivalent to:
function response(){
return function (dispatch){
//Some code here
}
}
So, basically what you can say is, it is a modern way of writing the same function. => dispatch => is returning a function that will be executed when the action will be invoked.
Hope this will help.
=> dispatch =>
is nothing but a syntactical sugar over a function returning another function. Since Fat-arrow functions => are used in place of normal functions.
Like
function abc(a,b){
return a+b;
}
is same as const abc = (a,b) => a+b ;
So you dont have to write return keyword.
So in your case its the same => dispatch => and the one below , its returning an anonymous function with . dispatch as its arguement
function response(){
return (dispatch){
//some code here
}
}
Hope it helps, feel free for doubts
I want to make multiple request in componentdidmount right now this is what i am doing,
componentDidMount() {
const {
getVehicleGroup,
getDrivers,
getFuelTypes,
getUnassignedDevices,
getCarMake
} = this.props;
getVehicleGroup();
getDrivers();
getFuelTypes();
getUnassignedDevices();
getCarMake();
}
and saga is attached with all these actions. Now i want to run another function but only when these requests. This is something i am looking for
Promise.all([getVehicleGroup, getDrivers, getFuelTypes, getUnassignedDevices, getCarMake])
.then(anotherFunction)
Here is my mapDispatch
const mapDispatchToProps = (dispatch) => ({
getVehicleGroup: () => dispatch(vehicleGroupRequest()),
getDrivers: () => dispatch(driverRequest()),
getFuelTypes: () => dispatch(fuelTypeRequest()),
getCarMake: () => dispatch(carMakeRequest()),
getUnassignedDevices: () => dispatch(unassignedDevicesRequest()),
updateCurrentDriver: () => dispatch(change('addVehicleForm', 'FK_driver_id', [])),
onSubmitForm: () => dispatch(addVehicleRequest())
});
Although I mostly use redux thunk, I think it should be similar in your case.
Try to do the following in your mapDispatch function:
getVehicleGroup: () => async dispatch(vehicleGroupRequest())
Async functions wrap as promises and behave mostly the same, allowing you to do something like:
Promise.All([]).then(nextAction)
IMHO the two most "neat" ways are:
with pure sagas: you dispatch one more action to start a saga that take all the actions you want to wait before starting the anotherFunction (but, depending on what you want to do with anotherFunction it could be useless)
you can use redux-saga-thunk to get a promise from every saga you are starting and gain all the advantages of redux-thunk. I haven't used it directly but I'll do as soon as I need to do something similar
I have several actions, that are need to be used with another one action,
more specific i have actions to work with doument and one action to save it, and i dont wont to repeat calling of save document, so i tried to create myself wrapper on the mapDispatchToProps and thunk.
I need to each action I pass to the method performed to thunk actions -
From
function changeAction() {
return: {
type: types.CHANGE
}
}
To
function change() {
return(dispatch, getState) => {
dispatch(changeAction())
saveDocument(getState());
}
}
I tried to create method to map actions to thunk
export function mapUpdatePresentationsToProps(actions) {
const mappedActions = {};
Object.keys(actions).map(action => {
mappedActions[action] = function() {
return (dispatch, getState) => {
dispatch(action)
dispatch(updatePresentation(getState()))
}
}
})
return mappedActions;
}
And I always get an error 'Actions must be plain objects. Use custom middleware for async actions.' Am i doing something wrong? I dont know how i can debug them. Will be grateful for any help.
I guess you need to change:
dispatch(action)
to something like:
dispatch(actions[action]())
Right now it seems that you try to dispatch a string