Implement global loading and error state with redux, thunk, routine and TypeScript

When dispatching async actions with redux-thunk, we usually have three actions for each thunk: REQUEST, SUCCESS and FAILURE. Imagine we have a thunk to fetch data, we would dispatch FETCH_DATA_REQUEST before we send the API request, then dispatch FETCH_DATA_SUCCESS when the request succeeds or dispatch FETCH_DATA_FAILURE when the request fails.

To store the loading state, we probably have a isFetching in our redux state tree as shown in the redux documentation and we change this state when we receive the REQUEST, SUCCESS and FAILURE actions.

If you have followed this way to implement the loading state, you probably already find that it is really tedious to write the boilerplate code again and again for each thunk.

Luckily, we now have a shiny small library called redux-thunk-routine (https://www.npmjs.com/package/redux-thunk-routine) to remove those boilerplate code that defines and dispatches actions while having better static type check at the same time (when using TypeScript).

But how about the isFetching state? Do we still need to write those repetitive code in reducer? Let’s have a look at a more elegant solution and take more benefits from using redux-thunk-routine — action names are defined in a standard pattern you can safely rely on.

For each routine, the library defines three actions by appending standard suffixes to the routine name. Let’s say we implement “fetch data” thunk using redux-thunk-routine: it will define three actions for by default: FETCH_DATA/REQUEST, FETCH_DATA/SUCCESS and FETCH_DATA/FAILURE.

Assume that all our actions are defined by redux-thunk-routine, then we can reduce them in a centralized manner to set isFetching state. Actually, to make the state more flexible, we will declare the loading state as a dictionary-like object — the routine name is the key, and the value(as boolean) indicates whether the routine is loading.

To express it in TypeScript, we write the type definition below:

Listing 0: Type Definition of Loading State

Then we can write the reducer to catch and handle all actions from the loading state perspective:

Listing 1: Reducer for Loading State

To use the state, we have the selectors below:

Listing 2: Selectors for Loading State

Note: the selectors above may cause re-render as we are creating selectors dynamically everytime when calling selectLoading. We should create selectors that accept arguments instead. See: https://github.com/reduxjs/reselect#q-how-do-i-create-a-selector-that-takes-an-argument

As we can see, the design of the loading state and selectors make it super flexible whenever we want to know if A GIVEN, ANY or SOME routines are loading.

Amazingly, the same principle also applies to the global error state. This time, let’s have a look at the implementation of all related parts in one file (using ducks):

Listing 3: Ducks for Error State

Again, you can find the demo code on GitHub and try the demo app online.

Thanks for reading :)

--

--

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Thor Chen

Thor Chen

Passionate JavaScript/TypeScript Developer with a Full-stack Background