I want to parse one excel sheet and before parsing I want some data from backend to map it.
So after clicking on Submit button, I want to trigger three actions one by one and store the response inside store. I am using redux-saga for this. After the three action (api calls), I will call the parsing function and do the parsing and mapping using that response I will be fetching from store.
I have tried dispatching the three actions one by one. But as soon as it reaches the network client i.e axios instance to call api it becomes async and the next line gets executed.
onSubmit = () => {
/* I will set the loader on submit button till the api is called and all parsing of excel sheet is done. */
this.setState({
showLoader: true,
}, () => {
this.props.getData1(); //Will be saving it in store as data1
this.props.getData2(); //Will be saving it in store as data2
this.props.getData3(); //Will be saving it in store as data3
/* After this I want to call the parsing function to parse the excel sheet data and map accordingly */
parseExcelData(sheetData); //sheet data is the excel data
}
So I expected that when I will call the 'parseExcelData' function, the data from store i.e data1, data2,and data3 will be available in that function. But all the api call happens after the sheet is being parsed. I have done it using saga generator functions and is working fine. But I want to know how to deal with this situation with redux.
Putting an api call (or any other async operation) into a saga does not make that action synchronous, it is still async. Separately, redux-saga really does not support getting a result from an action -- you trigger a saga with an action, so when the saga completes, it has no way to return a result to the code that originally triggered it. (You can try to work around this by passing a callback along with the action that triggers the saga, and have the saga call the callback, but I wouldn't recommend this approach.)
I would recommend implementing this without redux-saga
, using traditional action creators. The action creators would return promises that make the async api calls, and resolve with the result when they're finished. That might look something like this:
// action creator getData1, getData2, getData3
export const getData1 = () => {
return fetch(apiUrl).then(result => {
return result.json();
}).then(resultJson => {
// also fire an action to put it in the store here
// if other parts of your app need the data
return resultJson;
}).catch(err => {
console.error(err);
});
};
// react component
// assumes 1, 2, and 3 cannot be parallelized
// could also be written with .then instead of await
onSubmit = async () => {
this.setState({showLoader: true}, () => {
const result1 = await this.props.getData1();
const result2 = await this.props.getData2(result1);
const result3 = await this.props.getData3(result2);
});
}
You could have the action creators dispatch an action to put the data in the store instead of resolving the promise with the result. But that means you have to pick up the new data via the component's props, which probably means something in componentDidUpdate
that checks if the new props are different from the old props, and if so, calls the next data-fetcher. IMO that approach is much more awkward.