Dispatching asynchronous Side Effects inside synchronous Redux actions without using any middleware — React.

Subhayan Ghosh
Analytics Vidhya
Published in
3 min readApr 11, 2021

--

Photo by NeONBRAND on Unsplash

Asynchronizing stuffs are always a headache for programmers. setTimeout(), callbacks, promises, aync await, etc. — we got so many tools, still there are times when we feel lost in the synchronous paradigm of programming. I have been using React extensively at scale for the past one year. Developing high functional dashboards, UI optimizations, controlling data flow, and dealing with numerous API integrations are part of my daily job. Recently I had a situation where when the user resets a filter, the app should make two API calls from the frontend, one of whose queryparams would come from the data fetched from the other. In this blog, I am going to explain how I achieved that by making synchronous Redux actions asynchronous. So let’s dive in.

I am assuming here that you have a basic idea of how React and Redux works. According to Redux docs —

By itself, a Redux store doesn’t know anything about async logic. It only knows how to synchronously dispatch actions, update the state by calling the root reducer function, and notify the UI that something has changed. Any asynchronicity has to happen outside the store.

I being armed with JavaScript tools, just did a simple trick and very easily bypassed the above protocol to achieve my goal.

export const resetFilter = () => async (dispatch, getState) => {   
dispatch({ type: RESET_FILTER });
await dispatch(callAPI_1());
const {
mainComponent: { api1_data },
} = getState();
await dispatch(
callAPI_2(api1_data.param1, api1_data.param2)
);
};

This is pretty much everything I did. callAPI_1 and callAPI_2 are already defined redux actions where I am calling each API. The resetFilter action is triggered when the user resets the filter, and the app needs to recall the APIs with new params. The trick part here is that the queryparams of callAPI_2 is coming from the new state of callAPI_1 and since Redux actions are synchronous, the whole system fails without async-await. By using async-await, we wait for the first API call to complete, take it’s data and pass it to the queryparams of the second API call before triggering it. And like this again aync-await saves the day!

For complex situations you may need to use some Redux middleware like redux-thunk to make the actions asynchronous. But for smaller use cases like this, my approach will suffice. This can also be done using setTimeout(), callbacks, or promises but I prefer async-await (es6 yaay!!).

There may be a use case where you are making the same type of API calls but you are doing it as a Side Effect instead of from actions. The logic will be same but we need to call the callAPI_1 and callAPI_2 actions from a useEffect hook like this:

useEffect(() => {
async function getData() {
await callAPI_1();
await callAPI_2(api1_data.param1, api1_data.param2);
}
getData();
}, [callAPI_1]);

Remeber that promises and useEffect( async() => …are not supported in React but you can call async function inside an effect. Also there's one more React hooks rule that you should always remember:

Don’t call Hooks inside loops, conditions, or nested functions. Instead, always use Hooks at the top level of your React function, before any early returns. By following this rule, you ensure that Hooks are called in the same order each time a component renders. That’s what allows React to correctly preserve the state of Hooks between multiple useState and useEffect calls.

Additional tip: There will always be boundaries but you as a programmer can always use the already available tools to create magic.

Thanks for reading through. I will highly appreciate your reviews and suggestions. Do let me know in the comments if you have some other optimization techniques in mind.

If you found it useful, please give me a clap and share it with your fellow devs. Don’t hardcode, code hard!

Subhayan Ghosh

LinkedIn | Twitter | Instagram

--

--

Subhayan Ghosh
Analytics Vidhya

Engineering & Product| Writes about Data and Full Stack optimizations | Building for the Web