Async Dispatch Chaining with Redux-Thunk
Tags: react, redux, javascript, api
Published: 2020-07-03 11:20:57

---
title: Async Dispatch Chaining with Redux-Thunk
published: true
description: Redux-Thunk provides a good way of solving the complexity of asynchrony in JavaScript via dispatch chaining. Plus, it makes async code more reusable.
tags: react, redux, javascript, api
canonical_url: https://blog.jscrambler.com/async-dispatch-chaining-with-redux-thunk/
cover_image: https://blog.jscrambler.com/content/images/2020/07/jscrambler-blog-async-dispatch-chaining-with-redux-thunk.jpg
---

Asynchrony in React-Redux is often done [via a thunk](https://blog.jscrambler.com/asynchronous-operations-in-react-redux/?utm_source=dev.to&utm_medium=referral&utm_campaign=async-dispatch). This thunk function is _middleware_ that unlocks async operations by deferring execution. In this take, we’ll dive into what happens when there is more than a single async request. Async code is unpredictable because completion is not known ahead of time and multiple requests complicate things.

The use case is not unheard of - Ajax calls often fire at initial page load. The app then needs to know when all calls finish to allow user interaction. Firing multiple requests from different parts of the Redux store and knowing when it’s ready is hard.

The complete sample code is available on [GitHub](https://github.com/JscramblerBlog/async-dispatch-chaining-redux-thunk).

Begin with `npm init` and add this to the `package.json` file:

```json
"scripts": {
  "start": "node index.js",
  "server": "json-server --watch db.json"
}
```

Then, put in place all dependencies:

```shell
npm i redux redux-thunk axios json-server --save
```

For the `json-server` create a `db.json` file and create these resources:

```
{
  "posts": [{"id": 1, "title": "dispatch chaining"}],
  "profile": {"name": "C R"}
}
```

This completes the back-end API. Now, imagine a React/Redux app that has profile and post info in the store. We’ll create actions to mutate data, a flag to know when it’s finished, and a reducer.

The typical code might look like:

```javascript
const redux = require('redux');
const thunk = require('redux-thunk').default;

const UPDATE_POSTS = 'UPDATE_POSTS';
const UPDATE_PROFILE = 'UPDATE_PROFILE';
const UPDATE_DONE = 'UPDATE_DONE';

const updatePosts = (posts) => ({type: UPDATE_POSTS, payload: posts});
const updateProfile = (profile) => ({type: UPDATE_PROFILE, payload: profile});
const updateDone = () => ({type: UPDATE_DONE});

const reducer = (state = {}, action) => {
  switch (action.type) {
    case UPDATE_POSTS:
      return {...state, posts: action.payload};

    case UPDATE_PROFILE:
      return {...state, profile: action.payload};

    case UPDATE_DONE:
      return {...state, isDone: true};

    default:
      return state;
  }
};

const store = redux.createStore(reducer, {}, redux.applyMiddleware(thunk));
const unsubscribe = store.subscribe(async () => console.log(store.getState()));
```

Because this runs in node, CommonJS is useful for including modules via `require`. The rest of this code should not surprise anyone who has written React/Redux code before. We’ve created a store with `redux.createStore` and applied the thunk middleware. As mutations ripple through the store, `store.subscribe` spits out what’s in the store to the console output.

## The problem in multiple endpoints

One question that comes to mind is, what happens when we have more than one endpoint? We need two async operations and a way to know when both are done. Redux has a way to do this that appears simple on the surface but becomes deceptive.

A naive implementation might look like this:

```javascript
const axios = require('axios');

const ROOT_URL = 'http://localhost:3000';

const loadPosts = () => async (dispatch) => {
  const response = await axios.get(ROOT_URL + '/posts');

  return dispatch(updatePosts(response.data));
};

const loadProfile = () => async (dispatch) => {
  const response = await axios.get(ROOT_URL + '/profile');

  return dispatch(updateProfile(response.data));
};

// Done is always set to true BEFORE async calls complete
const actions = redux.bindActionCreators({loadPosts, loadProfile, updateDone}, store.dispatch);
actions.loadPosts();
actions.loadProfile();
actions.updateDone(); // <-- executes first
```

The problem at hand lies in the fact Redux has no way of knowing _when_ both async operations finish. The dispatched action `updateDone` mutates state _before_ post and profile data are in the store. This makes async/await unpredictable since we don’t know when a dispatch with response data executes. We can wait for a response via `await` inside the thunk itself but lose all control outside of the function.

One potential solution is to lump all async code into a single thunk:

```javascript
// Illustration only, AVOID this
const combinedThunk = () => async (dispatch) => {
  const responsePosts = await axios.get(ROOT_URL + '/posts');
  dispatch(updatePosts(responsePosts.data));

  const responseProfile = await axios.get(ROOT_URL + '/profile');
  dispatch(updateProfile(response.data));

  dispatch(updateDone());
};
```

This is not ideal because of tight-coupling between concerns and less reusable code. Post and profile data may not live in the same place in the Redux store. In Redux, we can combine reducers and separate parts of the store into state objects. This combined thunk throws the code into chaos because we may need to duplicate code all over the store. Duplicate thunk code then becomes a high source of bugs or a maintenance nightmare for the next developer.

## Async chaining

What if I told you this problem is already partially solved? The keen reader may have noticed a `return` statement at the end of each thunk. Go ahead, take a second look:

```javascript
return dispatch(updatePosts(response.data));

return dispatch(updateProfile(response.data));
```

This returns an _actionable_ promise in Redux that can be chained. The beauty here is we can chain and reuse as many thunks while keeping store state predictable. These chains can be as long as necessary if it makes sense in the code.

With this in mind, it is possible to chain dispatched thunks:

```javascript
const dispatchChaining = () => async (dispatch) => {
  await Promise.all([
    dispatch(loadPosts()), // <-- async dispatch chaining in action
    dispatch(loadProfile())
  ]);

  return dispatch(updateDone());
};

const actions = redux.bindActionCreators({dispatchChaining}, store.dispatch);
actions.dispatchChaining().then(() => unsubscribe()); // <-- thenable
```

Note that as long as there is a return these dispatches are _thenable_. The bonus here is we can fire async dispatches in parallel and wait for both to finish. Then, update `isDone` knowing both calls are done without any unpredictable behavior. These reusable thunks can live in different parts of the store to maintain separation of concerns.

Below is the final output:

```text
{ posts: [ { id: 1, title: 'dispatch chaining' } ] }
{
  posts: [ { id: 1, title: 'dispatch chaining' } ],
  profile: { name: 'C R' }
}
{
  posts: [ { id: 1, title: 'dispatch chaining' } ],
  profile: { name: 'C R' },
  isDone: true
}
```

## Conclusion

Asynchrony in JavaScript is hard and unpredictable.

Redux/Thunk has a nice way to quell this complexity via dispatch chaining. If a thunk returns an actionable promise with async/await, then chaining is possible. This makes async code in different parts of the Redux store easier to work with and more reusable.

Finally, don't forget to pay special attention if you're developing commercial JavaScript apps that contain sensitive logic. You can protect them against code theft, tampering, and reverse engineering by starting your free <a href="https://jscrambler.com/signup?utm_source=dev.to&utm_medium=referral&utm_campaign=async-dispatch" target="_blank">Jscrambler trial</a> - and don't miss <a href="https://blog.jscrambler.com/protecting-your-react-js-source-code-with-jscrambler/?utm_source=dev.to&utm_medium=referral&utm_campaign=async-dispatch" target="_blank">our guide</a> for protecting React apps.

---

Originally published on the [Jscrambler Blog](https://blog.jscrambler.com/async-dispatch-chaining-with-redux-thunk/?utm_source=dev.to&utm_medium=referral&utm_campaign=async-dispatch) by [Camilo Reyes](https://blog.jscrambler.com/author/camilo-reyes?utm_source=dev.to&utm_medium=referral&utm_campaign=async-dispatch).