blog.jakoblind.no

Async Actions with Redux Thunk demystified

Many times have I heard people asking the following:

"Why is Async/Ajax in the advanced section of Redux docs? Shouldn't it be simplified and put in basics?"

Async/Ajax being in the advanced section of the official documentation can make developers afraid or hesitant to start learning about it.

Let’s take a closer look at how it works. Is it really that complicated?

Having a look at the source code

A great way of really learn something deeply is to code it yourself or read the source code. In my previous posts, we have coded a mini Redux and react-redux from scratch. Take a look if you haven’t already!

Today we are going to take a closer look at the code for Redux Thunk Middleware.

Redux Thunk Middleware

Redux is a minimalistic library that is possible to extend with middlewares. There are many middlewares for working with Async Actions, but the standard one to use is Redux Thunk Middleware.

The code for Redux Thunk is on Github and the whole implementation looks like this:

function createThunkMiddleware(extraArgument) {
  return ({ dispatch, getState }) =>
    (next) =>
    (action) => {
      if (typeof action === "function") {
        return action(dispatch, getState, extraArgument)
      }

      return next(action)
    }
}

const thunk = createThunkMiddleware()
thunk.withExtraArgument = createThunkMiddleware

export default thunk

Yes, that is the whole Redux Thunk middleware. 11 lines of code. Did you expect something bigger? :)

So what does the code do?

Main part

Most of the Redux Thunk code is actually boilerplate code for connecting to Redux as a middleware. The main part of the code is the three lines inside the if statement:

if (typeof action === "function") {
  return action(dispatch, getState, extraArgument)
}

When Redux Thunk is configured for your application, this code above will be run every time an action is dispatched from anywhere in the application. What the code does is that it checks if the action is a function and if it is, it calls that function with dispatch as the argument. It also passes in getState and extraArgument as arguments, but let’s not care about that for now.

To summarize:

  • When using Redux without middlewares, an action is always a plain Javascript object.
  • When using Redux with Thunk middleware, an action can either be a plain Javascript object, OR an action can be a function.

Let’s look at an example of how we can use it.

Usage of Redux Thunk

One example of an action creator that utilizes Redux Thunk could look like this:

function loadPostsAction() {
  return (dispatch, getState) => {
    // Do something here.
  }
}

A function is returned in which we have access to the Redux dispatch function. That function is the exact same dispatch function we use from other places in our Redux app to dispatch actions.

Now we can call this function how many times we want, whenever we want in our action creator. So if we work with Ajax, we might want to dispatch an action on success, and another action on failure.

We can just call dispatch in those two cases like this:

function loadPostsAction() {
  return (dispatch, getState) => {
    get("/api/posts").then(
      (payload) => dispatch({ type: "LOAD_POSTS_FULFILLED", payload }),
      (err) => dispatch({ type: "LOAD_POSTS_REJECTED" })
    )
  }
}

This time we call the dispatch function with a regular Javascript object as action like we usually do.

Conclusion

Redux is a powerful library but the basic principles are surprisingly simple. In addition to learning from tutorials and documentation, reading the source code will build you a deeper understanding.


tags: