Redux Middleware: Behind the Scenes

Redux is an exciting new JavaScript library by Dan Abramov designed to simplify state management in JavaScript applications. Redux middleware is an important Redux feature providing a “third-party extension point between dispatching an action, and the moment it reaches the store”. Simply put, it let’s us jump in the middle of all dispatched Redux actions, providing anything from simple logging to exception handling to properly processing asynchronous actions. If a dispatched action is the starting line and the application store is the final destination, middleware is the traffic cop(s) along the path ensuring each action is properly vetted.

What about the official docs?
Dan does an outstanding job in the official documentation explaining and exploring how Redux middleware reached it’s current state. Due to the thorough nature of the official documentation this article will not be exploring how to create or implement Redux middleware. Instead, I will pick up where us curious folks left off, diving into what’s going on behind the scenes in the middleware creation process to make this whole thing work. For those who were still fuzzy on middleware this will (hopefully) provide the final ‘light bulb’ moment!

The Goal
The goal of this article is to further demystify Redux middleware, building upon the official Redux documentation. The highly functional nature of middleware can be a bit intimidating at first (store => next => action =>) to those still getting acquainted with functional programming techniques. Through the process I will be touching on a few of these techniques in order to acquire a full grasp on the Redux source code. By the end, it is my hope you will be prepared to create and contribute awesome middleware of your own. At the very least we can pick up some neat, useful techniques from Dan’s code! Let’s get started!

Precursor – ES6/7/FP
The Redux codebase takes full advantage of ES6/7 features. If you are unfamiliar with this syntax it may be a bit confusing to read. Also, one popular functional programming method, compose, is used a fair amount in the code I am about to explore. As a result I have included a short explanation of compose below, as well as links to the ES6/7 features that are important to understand. It’s certainly worth the time to familiarize yourself with these concepts as they will come in extremely handy, either immediately with Babel or in the near future as the spec is fully implemented in native browsers. Feel free to skip past the next section if you are already familiar with this concepts.
ES6 Spread
ES6 Rest Parameters
ES7 Object Rest/Spread (Proposal – Stage 1)

Let’s Start Composing!
Function composition is an important functional programming technique used to snap together a group of small, focused functions into larger, more complex functions. Compose is a method that does just that, accepting multiple functions, continually passing the result of the previous function to the next until all provided functions are satisfied. Compose generally flows from right to left although similar left to right implementations can be found in popular JavaScript libraries (ex. flow in Lodash). Let’s see an example of a basic compose function.

As you can see, we are initially accepting two functions, returning a function that will call the first function, passing the result of the second. Redux supplies it own compose method, accepting an unspecified number of functions and, in the case of Redux middleware, returning a function. The source code can be seen below.

The last argument is passed right to left to all provided functions until the left-most function is resolved. Still confused? Let’s solidify this concept with a diagram below, in this case providing a number instead of a function as the last argument for the sake of demonstration. Assume the two functions involved, addTen and addTwenty, do exactly as they say.

Redux Compose

Redux Compose

The first parameter (0) is passed to the first supplied function, right to left, with the result being passed on until all functions are resolved. Now that we have a grasp on compose, let’s see how this is put to use in the Redux middleware source code!

Preparing our Middleware
*Note: To follow along you can clone jackielii’s Simplest-Redux-Example. For the sake of demonstration I am only adding two basic middleware functions to that example.
Let’s start by creating two basic Redux middleware functions to perform logging of all dispatched actions. This is the same logging code found in the official documentation.

The middleware signature of store => next => action might look strange at first glance but don’t worry, we are about to see why this works so well!

Applying Middleware
The first step in hooking up our custom middleware is invoking the applyMiddleware method with our previously created logger functions. The applyMiddleware method takes an unrestricted number of middleware, returning a function that accepts the Redux createStore method, ultimately returning a function accepting a Redux reducer (or combined reducers) and initial state.

Head spinning? Don’t worry, breaking this down as it happens makes it easy to reason about.

LoggerOne and LoggerTwo satisfy applyMiddleware’s initial parameters, while our immediate invocation of the returned function with the createStore method satisfies the parameters of the subsequent function. At this point, createStoreWithMiddleware is a function accepting our reducer (single in this case but could be combined), prepared to return our application store. You can think of createStoreWithMiddleWare like this, which is much easier on the eyes…

Line’s #4 and #5 are pretty self-explanatory, a new Redux store is created (remember next in this context is the Redux createStore method) and a reference held to the store’s dispatch action, to be used later. On line #8 a basic object is created with reference to our app store’s getState action (returns the state for the application) and a dispatch function accepting an action and invoking our store’s dispatch function with this action. Let’s look at lines #12 and 13 individually as this is where Redux middleware officially comes together.

On this line our array of provided middleware (loggerOne, loggerTwo) is being mapped over, creating an array of functions while satisfying the first parameter of our middleware (store => next => action =>) with the newly created middlewareAPI object from above. Each middleware function will now have access to our app stores getState method as well as a way to personally dispatch the action received (if needed). Finally, on line #13 we are composing our newly created array of middleware into our store’s new middleware wrapped dispatch function.

Quick reminder of the compose function syntax…

As we saw before, compose takes an unspecified number of parameters (in our case functions), passing right to left the current function to the next function in line. In this case we are satisfying the next parameter in our middleware functions from right to left, starting with the store.dispatch method which becomes the final link in the chain. This can be seen in the diagram below.

Compose Middleware

Compose Middleware

Finally, using the proposed ES7 object spread syntax (similar to Object.assign) we return our store object, substituting the default dispatch with our newly created, middleware wrapped dispatch method.

Let’s See It In Action!
Now that we have successfully included our middleware, let’s see how a Redux action flows through our previously composed dispatch function.

Middleware Action

Middleware Action

When an action is dispatched it flows from middleware to middleware via the next function until it finally reaches the end of the line, where state.dispatch is called. Pretty awesome functionality for just a few lines of code!

Conclusion
In conclusion, Redux middleware provides a solid access point between a dispatched action and the application store, allowing the implementation of whatever custom functionality fits our needs. This is a powerful tool to take advantage of when using Redux in your next JavaScript application. As always, feel free to drop me a line with any questions or comments and definitely keep an eye on Dan Abramov as he is doing amazing things in the JavaScript community. Until next time, happy coding!

  • Maik Diepenbroek

    Quite a rood read, thanks for more background information. Clearly written and more in depth then the basic docs. Thanks for the effort!

    • Btroncone

      Maik,
      Thank you for the kind words, I’m glad you enjoyed the article!

  • jpescione

    Good shit. thanks.

    • Btroncone

      Thanks for reading!

  • Chiehlun

    nice article!

  • Konos5

    Such a great article @Btroncone!
    It’s by far the best resource for explaining the redux middleware “magic” which fries the brains of most newcomers.

    My only remark has to do with the loggers’ output. It would be helpful to see the output of your loggers so that any doubts about the console.log order of the loggers is cleared up!

    All in all nicely presented with full detail making no false assumptions. Congrats!

    • Btroncone

      Thanks for the kind words and feedback!

  • Islam Ibakaev

    what about this version?
    const addTen = x => x + 10;
    const multByTen = x => x * 10;

    const compose = (…funcs) => x => funcs.reduceRight((composed, f) => f(composed), x);

    const addTenThenMultByTen = compose(multByTen, addTen);

    console.log(addTenThenMultByTen(5)); // 150

Next ArticleES6 Modules By Example