Multiple dispatch in componentDidMount - reactjs

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

Related

redux thunk wait data from a dispatch before to do an another dispatch

I'm trying to improve my code by trying to use redux thunk as well as possible but I've searched a lot, no solution corresponds to my research.
Basically, with the twitch API we have to make 2 API calls, one to get the authentication key and another to get the data from this key.
Here is my current code:
dispatch(getOauthKey())
}, [])
useEffect(() => {
if(refresh){
dispatch(getAllStreams(oAuthKey.access_token))
}
}, [oAuthKey.access_token])
Here I had to use a true/false with refresh to know when to dispatch or not and [oAuthkey.access_token] to restart the useEffect when the variable receives data.
It works but it's not optimized at all and I know you can chain dispatches with thunk but I couldn't do it. Here is what I tried to do:
const thunkA = () => (dispatch, getState) => {
dispatch(getOauthKey())
}
const thunkB = (key) =>(dispatch, getState) => {
dispatch(getAllStreams(key))
}
console.log(oAuthKey.access_token)
useEffect(()=> {
dispatch(thunkA()).then(() =>dispatch(thunkB(oAuthKey.access_token))
);
}, [])
And I have this as an error:
TypeError: Cannot read properties of undefined (reading 'then'). I specify that the first call api sends the key into the store so the oAuthKey comes from the latter
Sorry I'm really new to reactjs / redux / thunk and the problem doesn't jump out at me here haha.
thank a lot in advance
There are several options to do that. as a standard redux-thunk solution, you can use promise changing for dispatching the actions in the thunk.
First of all, you need to add this package: redux-promise-middleware with the official documentation.
Given a single action with an async payload, the middleware transforms the action to separate pending action and a separate fulfilled/rejected action, representing the states of the async action.
Now you can chain your actions:
const chainMyActions = () => {
return (dispatch) => {
const response = dispatch(thunkA());
response.then((data) => {
dispatch(thunkB(data.access_token))
})
}
}
Now you can call the sample chainMyActions function in your useEffect.

How does a react action have access to dispatch?

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.

Understanding async dispatch actions using redux thunk

I was just going though the files that dispatches ACTIONS in a reactjs app and basically came across the following function::-
// When app inits
export const init = () => async dispatch => {
dispatch({ type: TYPES.SET_LOADING });
await dispatch(getConfig());
await dispatch(getGenres());
dispatch({ type: TYPES.REMOVE_LOADING });
};
I am a bit confused as to what the async is doing ahead of the dispatch , i am used to seeing normal vanilla javascript async functions like so:
anasyncfunc = async () => {
// write you're code here
}
But the above code confuses me a little. Can somebody please explain this to me.
A function which uses the await keyword must me marked with async which you have pointed out in your example
anasyncfunc = async () => {
// write you're code here
}
In this function we can now use await since it was marked with async.
In the case of the thunk, we are effectively creating an outer function called init which when called will return an anonymous function. This anonymous function will accept dispatch as an argument and will make use of the await keyword, and as such needs to be marked with the async keyword.
In short, we really are just creating a function which will want to use await and therefor must be marked with async.
I hope this clarifies it.

Why async actions have a currying?

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);

Redux Thunk Sharing Async Object

If I have following thunk:
function postReq(body) {
return dispatch =>
superagent.post("/files")
.then(response => dispatch(actionCreator(response)));
}
How would I share the superagent request object with other parts of my code base? Would I pass it into the actionCreate and put it in the store?
I would like to abort the request on certain Events, that's the reason I am looking for this.
EDIT
To give more context to the Problem on hand. When a user uploads a file he has the option to abort the upload. As I am creating the superagent request within a thunk I need to pass the request object on to be able to call superagent.abort().
Well, first of all I would like to introduce you some ES6 features which would make your code WAY more readable. Right now you have:
function postReq(body) {
return dispatch =>
superagent.post("/files")
.then(response => dispatch(actionCreator(response)));
}
first you could use ES6 to make your function more readable in 2 steps:
Step 1
Update your action creator to be stored at a cost variable:
const postReq = (body) => {
return dispatch =>
superagent.post("/files")
.then(response => dispatch(actionCreator(response)));
}
Step2
Your function is returning a function so you can make it shorter and more readable with an implicit return:
const postReq = (body) => (dispatch) => {
superagent.post("/files")
.then(response => dispatch(actionCreator(response)));
}
Now, answering you could try to do what they expose here:
https://github.com/reactjs/redux/issues/1461#issuecomment-190165193
Which applied to your case would be something like:
const postReq = (body) => (dispatch) => {
superagent.post("/files")
.then(response => dispatch(actionCreator(response)));
const abort = superagent.abort.bind(superagent)
return { abort }
}
I have never done this myself but as far as I understand its binding the abort method to a variable which will be returned and executing the function stored there will call the abort method in the postReq context.

Resources