Redux Middleware - A tool you aren't using enough
If you are using redux to manage the state of your application, you must be familiar with redux middleware, and you probably have used the most common `redux-logger` middleware for debugging purpose. However, if you dive deep into redux middleware, you will find a lot more use cases, such as crash reporting, error handling, etc. and make your redux application more concise and centralized.
What is a redux middleware:
Definition from redux official docs:
- A “middleware” in redux is a higher-order function that composes a dispatch function to return a new dispatch function. It often turns async actions into synchronous actions.
- It provides a third-party extension point between dispatching an action, and the moment it reaches the reducer.
As you can see from diagram above, a redux middleware is used to intercept dispatched actions before they make it to the reducer. This means that when you call dispatch on an action, the action goes through a (or many) middleware before hitting the reducer - if it even makes it that far, but more on that later.
You can apply multiple middleware to a redux store, which means that the action goes through all the middleware before making it to the reducer. The order of execution is actually the order in which you pass the middleware to the store. Also, at any point in a middleware, you can choose to stop forwarding the action, which will end the cycle.
This is the signature of a redux middleware:
The above function signature is just a curried form of a function that takes three arguments. In case you are wondering why currying, you can read here(10 min read).
Let’s have a closer look at this function.
`store`: the Redux store instance that will be passed to your middleware.
`next`: a function that you need to call with an action when you want to continue the flow execution, which means passing the action to the next in line to either the following middleware or a reducer.
`action`: the action that was originally dispatched so that you can access it, apply logic based on the action, and eventually pass it on using next.
After you create this middleware function, you need to apply it to the redux store via `applyMiddleware` API from `redux`
Here we have applied two middleware, logger and crashReporter. Now let’s see a couple of examples.
In the logger middleware above, whenever there is an action being dispatched, we will start logging and grouping by the action type and after calling `next(action)`, which means passing the action to the next middleware, we are logging the current state of the whole store. Simple right?
This crash reporter middleware uses `Raven` as a third-party library to handle crashes when actions are being dispatched and send the causing action and the real-time state to Raven for analysis.
In this vanillaPromise middleware, we are checking if the action is a promise by checking the action’s thenproperty. If it’s not, we just pass it to next middleware or the reducer. If it is and if the action is resolved, we are dispatching the result and because we are returning the dispatch so the caller can handle the rejection.
Redux middleware are an essential tool that offers tremendous flexibility for action manipulation and makes redux applications more maintainable. There are many more redux middleware out there. The followings are a few commonly used middleware:
Keep exploring more use cases and start building your own redux middleware.