Managing asynchronous actions in Redux
Tags: thunk, redux, middleware, asynchronous
Published: 2019-07-08 18:07:08

---
title: Managing asynchronous actions in Redux
published: true
tags: thunk,redux,middleware,asynchronous
canonical_url: https://blog.logrocket.com/managing-asynchronous-actions-in-redux-1bc7d28a00c6
---

### Async actions in Redux with Thunk or custom middleware

![](https://cdn-images-1.medium.com/proxy/0*EOyjV_v3t5SymHMO)

As you know, [Redux](https://redux.js.org/) provides you with an elegant approach to manage the state of a JavaScript application. Its infrastructure is based on functional foundations and lets you easily build testable code. However, the flow of Redux tasks to manage the state of an application is completely synchronous: dispatching an action immediately generates the chain of calls to middlewares and reducers to carry out the state transition.

How can we enable the state transition of an application via asynchronous actions? How to enable, for example, state transitions involving a request to a Web server or the use of a timer? How do we integrate our application state with the data generated by an asynchronous action, while complying to the Redux architectural pattern?

### Splitting the asynchronous action

The common approach to integrate asynchronous tasks into the Redux architecture is to break an asynchronous action into at least three synchronous actions.

An action informing that the asynchronous task:

- started
- was successfully completed
- failed

Each of these actions changes the application state and keeps it in line with what is happening during the asynchronous task execution.

Implementing this approach requires that you dispatch the action that starts the asynchronous task. When the asynchronous task ends, a callback should manage the outcome of the asynchronous task and appropriately update the state with a positive or negative response.

That said, you may be tempted to support asynchronous actions by modifying their reducers, i.e. making sure that the reducer intercepting that action starts the asynchronous task and manages its outcome. However, this implementation violates the constraint that states a reducer to be a pure function. In fact, the result of an asynchronous task by its nature is based on a side effect.

So, let’s take a look at a couple of valid solutions to this problem.

[![](https://cdn-images-1.medium.com/max/1024/1*GPjaPKNNUYHU8EsA3Z0JGA.png)](https://logrocket.com/signup/)

### Asynchronous actions and Thunk

A first approach is based on the [Thunk middleware](https://github.com/reduxjs/redux-thunk). The role of this [middleware](https://redux.js.org/advanced/middleware) is very simple: verify if an action is a function and in which case execute it. This simple behaviour allows us to create actions no longer as simple objects, but as functions, which therefore have business logic.

So, in order to solve our problem with asynchronous tasks, we can define an action as a function that starts an asynchronous task and delegates its execution to the thunk middleware. Unlike the reducer, middleware is not required to be a pure function, so the thunk middleware can perform functions that trigger side effects without any problem.

Let’s put these concepts into practice by implementing a simple application that shows a [Ron Swanson](https://en.wikipedia.org/wiki/Ron_Swanson) random quote from a [_specialized_ API](https://github.com/jamesseanwright/ron-swanson-quotes). The markup of the Web page appears as follows:

```jsx
<div>
  Ron Swanson says:
  <blockquote id="quote"></blockquote>
</div>
```

For the JavaScript side, you need to get the [_redux_](https://redux.js.org/introduction/installation) and [_redux-thunk_](https://github.com/reduxjs/redux-thunk#installation) dependencies and import a few items in the module as shown below:

```jsx
import { createStore, applyMiddleware } from 'redux';
import thunk from 'redux-thunk';
```

As said before, you must first define three synchronous actions that represent changes in the state during the execution of the asynchronous task. Let’s define the following constants:

```jsx
const QUOTE_REQUESTED = "QUOTE_REQUESTED";
const QUOTE_RECEIVED = "QUOTE_RECEIVED";
const QUOTE_FAILED = "QUOTE_FAILED";
```

As you can see, they represent the three phases we described above.  
Let’s now define an action creator for Thunk:

```jsx
function getQuoteAction() {
  return function(dispatch) {
    dispatch({
      type: QUOTE_REQUESTED,
    });
    
  fetch("https://ron-swanson-quotes.herokuapp.com/v2/quotes")
    .then(response => response.json())
    .then(data => dispatch({
        type: QUOTE_RECEIVED,
        payload: data
      }))
    .catch(error => dispatch({
        type: QUOTE_FAILED,
        payload: error
      })
    );
  }
}
```

The first thing you can notice is that the action creator _getQuoteAction()_ returns a function, as expected. The returned function starts dispatching the synchronous action QUOTE\_REQUESTED and executes _fetch()_ to actually start the asynchronous task, the HTTP request. Then, it dispatches one of the other two synchronous actions accordingly to the outcome of the asynchronous HTTP request.

Once we defined the transformation of an asynchronous action into three synchronous actions, we need to manage their impact on state transitions. So, let’s define the initial state of our application and the reducer that will manage quote retrieving:

```jsx
const initialState = { data: [], status:"" };

function quotes(state = initialState, action) {
  switch (action.type) {
    case QUOTE_REQUESTED:
      state = Object.assign({}, state, {status: "waiting"});
      break;
    case QUOTE_RECEIVED:
      state = Object.assign({}, state, {data: […action.payload], status: "received"});
      break;
    case QUOTE_FAILED:
      state = Object.assign({}, state, {status: "failed", error: action.payload});
    break;
  }
  
  return state;
}
```

The structure of the application state consists of a _data_ array, containing the list of quotes to show (in our case we will have one quote), and a _status_ string, representing the current status of the asynchronous action. The _status_ property is not strictly required for the correct behaviour of the application, but it may be useful in order to give feedback to the user. The _quotes()_ function implements a standard reducer by handling the three synchronous actions and generating the new application state accordingly.

The next step is to create the Redux store by specifying the use of the Thunk middleware, as shown by the following statement:

```jsx
let store = createStore(quotes, initialState, applyMiddleware(thunk));
```

Finally, you have to manage the UI connecting it to the Redux store, as the following code shows:

```jsx
const quoteElement = document.getElementById("quote");

store.dispatch(getQuoteAction());
store.subscribe(() => {
  const state = store.getState();
  
  if (state.status == "waiting") {
    quoteElement.innerHTML = "Loading…";
  }
  if (state.status == "received") {
    quoteElement.innerHTML = state.data[0];
  }
});
```

As you can see, you dispatch the starting action by calling the _getQuoteAction()_ creator and then subscribe to state changes. When a state change occurs, you check the _status_ property value and inject the text inside the blockquote HTML element accordingly.

The final result in your browser will look like the following:

![](https://cdn-images-1.medium.com/max/842/0*EOyjV_v3t5SymHMO)

Try this code on [CodePen](https://codepen.io/andychiare/pen/aPgxgp).

### Creating your own custom middleware

Redux Thunk elegantly solves the problem of managing asynchronous actions in Redux. However, it forces you to make the action creator’s code more complicated by sending the HTTP request and handling the response.

If your application heavily interacts with the server, as often it happens, you will have a lot of duplicate or quite similar code within the action creators. This distorts the original purpose of the action creators: creating an action based on parameters. Perhaps, in these cases, it is more appropriate to create an ad hoc middleware. The goal is to isolate the code that makes HTTP requests to the server in a special middleware and to restore the action creator to its original job.

So, let’s define a constant that identifies a meta-action for the HTTP request. We call it a meta-action because it is not the action that will directly modify the application state. Indeed, it is an action that will trigger an HTTP request and which will cause changes to the application state as a side effect by generating other actions.

The following is our constant definition:

```jsx
const HTTP_ACTION = "HTTP_ACTION";
```

Along with this constant, you need to define the constants that identify the actual action and the related synchronous actions to implement the HTTP requests, as we have seen before:

```jsx
const QUOTE = "QUOTE"
const QUOTE_REQUESTED = "QUOTE_REQUESTED";
const QUOTE_RECEIVED = "QUOTE_RECEIVED";
const QUOTE_FAILED = "QUOTE_FAILED";
```

Now, you need the _meta-action creator_, that is an action creator that takes a plain action object as input and wraps it in order to create an asynchronous action to be handled via HTTP. The following is the meta-action creator that we are going to use:

```jsx
function httpAction(action) {
  const httpActionTemplate = {
    type: "",
    endpoint: null,
    verb: "GET",
    payload: null,
    headers: []
  };
  
  return {
    HTTP_ACTION: Object.assign({}, httpActionTemplate, action)
  };
}
```

You may notice that it returns an object with the HTTP\_ACTION constant as its only property. The value of this property comes out from the action passed as a parameter combined with the action template. You notice that this template contains the general options for an HTTP request.

You will use this meta-action creator whenever you want to create an asynchronous action that will involve an HTTP request. For example, in order to apply this approach to retrieve the Ron Swanson random quotes described before, you can use the following action creator:

```jsx
function getQuoteAction() {
  return httpAction({
    type: QUOTE,
    endpoint: "https://ron-swanson-quotes.herokuapp.com/v2/quotes"
  });
}

```

As you can see, any asynchronous action that involves an HTTP request can be defined by invoking the _httpAction()_ meta-action creator with the minimal data to build up the request. You no longer need to add here the logic of synchronous actions generation, because it was moved into the custom middleware, as shown by the following code:

```jsx
const httpMiddleware = store => next => action => {
  if (action[HTTP_ACTION]) {
    const actionInfo = action[HTTP_ACTION];
    const fetchOptions = {
      method: actionInfo.verb,
      headers: actionInfo.headers,
      body: actionInfo.payload || null
    };
    
    next({
      type: actionInfo.type + "_REQUESTED"
    });
    
    fetch(actionInfo.endpoint, fetchOptions)
      .then(response => response.json())
      .then(data => next({
        type: actionInfo.type + "_RECEIVED",
        payload: data
      }))
      .catch(error => next({
        type: actionInfo.type + "_FAILED",
        payload: error
     }));
  } else {
    return next(action);
  }
}
```

The middleware looks for the HTTP\_ACTION identifier and replaces the current action with a brand new action with the \_REQUESTED suffix. This new action is inserted in the middleware pipeline via _next()_. Then, it sends the HTTP request to the server and waits for a response or a failure. When one of these events occurs, the middleware generates the RECEIVED or FAILED actions as in the thunk-based approach.

At this point, the only thing you need to change to achieve the same result as in the thunk-based approach is the store creation:

```jsx
let store = createStore(quotes, initialState, applyMiddleware(httpMiddleware));
```

You are saying Redux to create the store by applying your custom _httpMiddleware_ instead of the Thunk middleware. The implementation of the reducer and the UI management remain as before.

You can try the implementation of this approach on [CodePen](https://codepen.io/andychiare/pen/roXxpB).

### Conclusion

In summary, we discovered that any asynchronous action can be split in at least three synchronous actions. We exploited this principle to implement two approaches for managing asynchronous actions while using Redux.

You may consider the first approach, based on the standard Thunk middleware, easier, but it forces you to alter the original nature of an action creator.

The second approach, based on a custom middleware, may seem more complex at a first glance, but it is much more scalable and maintainable.
* * *
### Plug: [LogRocket](https://logrocket.com/signup/), a DVR for web apps

[![](https://cdn-images-1.medium.com/max/1024/1*s_rMyo6NbrAsP-XtvBaXFg.png)](https://logrocket.com/signup/)<figcaption><a href="https://logrocket.com/signup/">https://logrocket.com/signup/</a></figcaption>

[LogRocket](https://logrocket.com/signup/) is a frontend logging tool that lets you replay problems as if they happened in your own browser. Instead of guessing why errors happen, or asking users for screenshots and log dumps, LogRocket lets you replay the session to quickly understand what went wrong. It works perfectly with any app, regardless of framework, and has plugins to log additional context from Redux, Vuex, and @ngrx/store.

In addition to logging Redux actions and state, LogRocket records console logs, JavaScript errors, stacktraces, network requests/responses with headers + bodies, browser metadata, and custom logs. It also instruments the DOM to record the HTML and CSS on the page, recreating pixel-perfect videos of even the most complex single page apps.

[Try it for free.](https://logrocket.com/signup/)
* * *
The post [Async actions in Redux with Thunk or custom middleware](https://blog.logrocket.com/managing-asynchronous-actions-in-redux-1bc7d28a00c6/) appeared first on [LogRocket Blog](https://blog.logrocket.com).