Efficient asynchronous flow with React and Redux

Mathieu Savy
Glose Engineering
Published in
5 min readOct 24, 2017

At Glose, we are building the reading platform of the 21st century, serving millions of eBooks to millions of readers across the world, giving them access to an incredible amount of knowledge right under their finger.

Our interfaces can be complex as we offer a lot of interactions for the readers, and that imply a certain amount of HTTP requests between client and server. That’s why we need to have an efficient flow to handle it.

React and Redux allow us to have a great and efficient control over our state and user interface. When it comes to asynchronous actions that interact with an API (or whatever, API is just the most common example), things can became redundant and laborious. We will see a way to have a great async flow without writing tons of identical code.

This article will only deal with thunks, which are actions that return functions. If you are not familiar with this concept, I invite you to have a look at redux-thunk middleware.

The naive way

The most common way to deal with asynchronous actions is with thunks. Thunks are actions that are not objects but functions that can dispatch other actions — and eventually do other things, but let’s keep it simple for now.

Taking a simple action we want to perform, getting some info about an organization on GitHub. We want to know two things:

  • when the request starts
  • when the request ends (and if it succeeded or failed)

With a thunk, it will look like the following:

First we are dispatching aFETCH_ORG_REQUEST action, so that the user interface can handle the loading state.

Then, the fetch action is performed. It’s the actual HTTP request. If you don’t know about fetch, check it out, it’s now native on modern browsers and there is a good polyfill for older ones.

When the fetch is over, we have two possibilities:

  • either it has failed, then an error is raised an the FETCH_ORG_FAILED action is dispatched
  • or everything went well (yay!) and the FETCH_ORG_SUCCESS action is dispatched with the result of the request

Pretty simple isn’t it? Only 26 lines of code (yes it could be less, but I like to be able to read my code later without having a headache). Now imagine a second action to fetch the repositories of an organization. Yup, same stuff, probably around 25–30 lines of code too.

Now think about a large scale project with dozens or hundreds of this kind of HTTP requests. Three actions: ‘request’, ‘success, ‘failed’. Same code, hundreds of times. Pretty boring, and massive. It will represent a lots of code, for absolutely no interest, it’s only mechanic.

We have to factorize that.

Factorize all the things!

Okay, what can be factorized here? The three kinds of actions for a single one. Let’s start with that.

We should make a function that returns our action creator (that itself return a function — a thunk). Our function, let’s say asyncAction will take the name of actions to dispatch and the URL, the suffix will be added automatically.

That’s not so bad. But, there are a lot of issues with that:

  • We don’t handle arguments. This action would have been a lot better if we could give facebook as an argument to it, and simply call fetchOrganization('facebook').
  • Event if we took all arguments with an ...args at the function returned on line 2, we would lose the information of the argument name, and this is a really important information. We don’t want to refer to our arguments with their position on args array.

Function is not so bad, but it didn’t work. Do you know what has been a cool addition to ES6? Classes.

Do it classy

Even if React and Redux world put a lot of accent on functional programming, I find OOP very elegant in this kind of situation.

What do we want here? A way to express easily all of our asynchronous actions that talks to our API without repeating ourselves.

We can make a class per action, its constructor handling the arguments (if any), a method to perform the call. And that’s it. The parent class takes care of all the stuff discussed before.

This kind of action will look like this:

Pretty neat isn’t it?

Now, here is the magic behind AsyncAction parent class.

The parent class only defines a toThunk method, that we will use in just a minute. The logic is the same as before, dispatch an action, make the request, dispatch according to the result.

Before we can make this work, we have to make a small transformation, because Redux doesn’t know what to do with a class. That’s why we defined a toThunk method, because Redux understands thunks with redux-thunk middleware.

We just have to intercept all actions that are AsyncAction instances, and continue working with the thunk of it. To do that, let’s create a small middleware:

Don’t forget to add this middleware before redux-thunk middleware when creating your redux store (or else transformation to thunk will occur after the action is treaded by redux-thunk middleware), and we’re done.

If you are not familiar with Redux middlewares, I invite you to read the documentation about middlewares.

Now, you can simply dispatch your action like dispatch(new GetOrganization('facebook')). It seems unusual to have a class instanciation with a dispatch, but it’s nothing and you know what is working under, so it’s not a big deal.

Going further

This way to handle asynchronous actions is one among a lot of another. There are great libraries with different approaches like Redux-Saga for example. It’s up to you to learn different ways to deal with your asynchronous flow and to choose the one that better fits your needs.

What I like about the approach I am presenting here is that it’s lightweight and very extensible. At Glose, we are using it, with some additions for error handling, before request hooks, etc.

The code is simple and you can easily add some logic to answer different issues about your asynchronous flow.

--

--

Mathieu Savy
Glose Engineering

Full time geek-diver. Staff Engineer at @Medium/Glose - https://glose.com. Former @EPITA student, 2015