Trying to understand Redux and Redux Middleware

What exactly is Middleware and why do you need it?

Vaibhav Namburi
9 min readMay 23, 2016

The Build up.

I’ve asked this question only once, because — the second you figure out why, you’ll realise how prettyful they are. Also, i’m going to assume you are aware of React and Redux and the entire ecosystem to some extent. However, i’ll try go through concepts as they come along, including JS concepts where needed :)

For those alien to Node or any language not familiar with this concept, Middleware’s are functions that you repeatedly execute between two events, that may be between receiving a request and executing a response (in the backend), similarly we take this concept and place it with the Redux data flow cycle.

When did I realise I needed Redux Middlewares? Well I wanted to make a promise based request from my actions to the back end to receive some data. I then wanted to take this data and save it into my global store via a reducer, however — when this request reached my reducer, it was still in a pending promise state, thus my component that depended on this data couldn’t render.

So over here, i’m making a request to a URL I defined somewhere in the file, and this request is invoked when my component that is meant to host the list of banks is meant to be loaded.

The use of React Component LifeCycle Methods

This invocation is done using handy React Component LifeCycle methods. These methods are extremely valuable, the TL;DR is that — based on the stage of the component’s life, i.e is it just about to be rendered onto the page, is it going to receive new props? or is it just about to be demounted from the page?, functions can be executed. Have a read here:

Based on this simple request, the reducer reciprocates with simplicity as well.

What is a reducer exactly?

Reducer is a function that takes the existing redux state, a mutating effect(action) and returns an updated version of the state to be fed into the global store.

Using ES7 spread operators, we de-construct the existing array and add onto the object the mutating data. However disaster will strike here, as the action’s payload which was a promise would have not resolved as of yet. One way of handling this would be to resolve it within the reducer case and pass the resolved state.

As you can see, resolving the payload, attaching it to a variable and then using that to update the state attribute is a lot of work, and this process may need to be repeated for every single request to the back end. To stick with DRY programming principles we then implement Middleware, which will conveniently fit between actions and reducers.

How I understand redux:

I use this analogy for understanding redux:

  • Think of your redux store as a building
  • Each reducer as a floor manager responsible for the state of a floor (each key in the global redux state) containing many offices
  • Actions can be thought as construction or delivery people each of who’s goal is to change (mutate) each floor’s plan

What’s the process ?

  • Actions are dispatched from a React component.
    — Actions can be thought as workers who carry two things :
    an access key to only one particular floor and “mock furniture” to take upstairs.
  • The worker is not aware of where he has to deliver so they visit each office on each floor trying to gain entry.
  • When their access key matches, they place the fix the furniture, and ring their manager
    — the manager creates an exact copy of the floor offsite and replaces that entire floor in the building with the new changes in place.
  • Middlewares act as the pedantic security guards next to the lifts.
  • Taking the example of Redux-Promise:
    It checks if anyone entering the lift is bringing in unassembled “ furniture”, work in the state of pending (promises), and if so, they make you wait till you assemble it and grant permission.

Converting this analogy into the actual flow.

Taking the example of a component needing data from a server to load onto a list :

  • On component mounting, an action is dispatched which sends an axios request to the back end, the retrieved data is contained within the payload attribute of the action
  • Just before reacting the reducer, the action passes through the redux-promise middleware we will install, this will resolve the promise and send the resolved data to the reducer
  • The action passes through all the reducers and when it fits the right action type, the payload of the action is used to return a completely new version of the previous state with the new data in place
  • This causes a redux flush, i.e all the React components connected to the redux store, depending on the global state properties that just changed will be re-rendered and flushed with the new data. This is immediately reflected and showcased.

With that being said, back to Middlewares and how they actually work. Middlewares have a rather noisy structure, but if we go in and understand the reason behind all of the extra lines of code and complexity it’ll make sense. Especially so when we go into understanding on a broader scale how some of redux’s helper functions work.

This is my index.js file, i.e the entry point for my module bundler (webpack). Lets go through it:

  • Theres a bunch of core imports, middleware and the App component along with the combinedReducers result
  • We then use the applyMiddleware function shipped with redux and invoke it with all the middlewares (we’ll be visiting this soon), the returned function is then invoked with the createStore function: http://redux.js.org/docs/api/createStore.html
  • To the ReactDOM.render function we pass in a provider instance with a store prop which will create a store using the reducers while keeping in mind the purpose of the middleware
  • The provider acts as a convenience factor by making the global redux store available to every connected component rather than individually passing it on each time. Have a read at the docs if you wish, but thats pretty much it : https://github.com/reactjs/react-redux/blob/master/docs/api.md#provider-store
  • This is rendered onto the HTML using a div with the class target : container

All this talk and still no middlewares, patience is virtue my friend.

Middlewares’ structure as on now

This uses ES6 syntax and looks way confusing. Lets go ahead and make this ES5, with a little less noise.

Structure of a middleware logger function

Okay, so not exactly perfect, but at least it’s a little more verbose.Lets walk through it.

P.S this is pretty much a currying function,

What is Currying?

Without going into too much depth, think of currying as a convenience being used when you don’t want a function to contain many arguments, instead you use one of JavaScript’s specialities to perform currying.

Currying helps with :

  • Higher order functionalities
  • Memoization
  • Avoiding passing the same arguments again and again.

From the above structure it’s safe to assume that the function needs to be invoked thrice.

ApplyMiddeware architecture

Moving on we really need to dive into how applyMiddleware really works to wrap our heads around this. The link to the code is :

Here’s the image of it, it you’re too lazy to click on it.

Apply Middleware function

Seems like a mouthful, but I promise you its not bad. Alright, line by line.

export default function applyMiddleware(…middlewares) {

This is just the function declaration, the *…* in front of the argument is ES7's spread operator, I encourage you to look into it.

return (createStore) => (reducer, initialState, enhancer) => {

applyMiddleware returns a function, which is invoked with the createStore :

var dispatch = store.dispatch

It assigns the Redux store’s dispatch function to a locally defined variable

var chain = []

Predefine a array to which we will map data

var middlewareAPI = {
getState: store.getState,
dispatch: (action) => dispatch(action)
}

We define an object setting the getState attribute from the store itself and the dispatch attribute from the local dispatch we defined.

chain = middlewares.map(middleware => middleware(middlewareAPI))

Array.prototype.map : How does it work?

It loops through the middlewares’ argument invoking each middleware with the middlewareAPI object. This is our first middleware invocation, i.e this is passed in as the store in the main middleware function, i.e line 1 in the picture of the middleware logger function

dispatch = compose(…chain)(store.dispatch)

Redux’s Compose function

Compose is a function shipped with Redux and it rightReduce’s all the middleware functions, invoking the last middleware with the Redux store’s dispatch function. So if we had a series of middleware in the chain such as

[y,b,x,d]

after the compose function we are returned :

(…args) => y(b(x(d(…args))))

credits to Dan Abramov on being a genius

More on that in the link below :

How does reduce work?:

_.each works exactly like the native each, except it takes the collection as an argument rather as a prototypal method. Following the native reduce architecture:

  • it takes an iterator and an accumulator as arguments.
  • If we don’t provide an accumulator, the function sets the first element in the collection as the accumulating value.
  • Iterating function’s first argument is the accumulating value, the second is the element in the collection
  • The accumulator is updated with the returned value of the iterator which is returned at the end of the each loop

So when the compose function is executed, it would have returned a function that would be then invoked with store.dispatch as seen on line 12 of the ApplyMiddleware function. The important part to understand is, the same dispatch function is used through all the middlewares to keep a unison in the result being achieved. All this returns what becomes the dispatch function for the store.

It is hosted within an anonymous function that is returned and invoked with the createStore function which takes in the combinedReducers as it’s initial argument, as seen and explained on line 2.

Wow that was a lot, it took me a while as well, so read over it as many times as you want and most importantly refer to the actual code with the links provided.

With this set in mind, lets write down, how we’ll approach creating our own redux-promise middleware.

Re-writing a basic Redux-Promise by ourselves

To check if an action’s payload contains a promise, we tap into the then function native to a Promise object. If this doesn’t exist, i.e it’s not a promise, then we go ahead and dispatch it like any other action.

If it does consist of a then function, all we do is, resolve the Promise, update the present action’s payload with the resolved data and then interestingly invoke the store’s dispatch with this ResolvedAction.

The reason for this is straightforward; the order of middleware’s are not curated, nor are they meant to be. Some middlewares may require an action not to be a promise but don’t necessarily check for it. So for the sake of these, we do a master dispatch, so that the now resolved version of the action enters the middleware chain again, this time round however it dispatches normally since the action no long contains a promise.

That’s pretty much it folks, I know — it can be really intimidating and overwhelming for some, but trust me, just read though this again and again along with the actual redux docs (which are honestly fantastic) and it’ll eventually make sense.

All the best!

--

--