Search code examples
node.jsreactjsreduxreact-reduxmiddleware

What is the difference between a reducer and middleware?


I'm having a little trouble understanding the difference of application between a reducer and middleware. A number of sites describe middleware even giving precise definitions:

It provides a third-party extension point between dispatching an action, and the moment it reaches the reducer.

Or:

Middleware is created by composing functionality that wraps separate cross-cutting concerns which are not part of your main execution task.

But from these all I understand is that there is a difference, just not what. From what I can tell, the difference is that one takes an action and passes that action on, and the other takes an action and a state and "passes the state on". But you still have access to the store in the midddleware. So store and action both go through the middleware and then reducers. So a reducer could perform logging.

While logging seems like an obvious application for middleware, there are more ambiguous examples. For example, writing in some trivial authentication into a module, you could use a middleware function to take an action sent by a user and determine their level of authentication:

import { getAuthLevel } from './auth';

export default store => next => action => {
  return next({...action, auth: getAuthLevel(action.clientId)});
}

You might have a bunch of users like this:

{
users: [{
  clientId: 'bobsUnqiueClientId',
  user: 'Bob',
  password: 'ilikecats',
  authlevel: 'OVERLORD'
}, {
  clientId: 'anotherUniqueClientId',
  user: 'Alice',
  password: 'boblikescats',
  authlevel: 'MINION'
}]}

Then you might have actions that correspond to different authentication levels. You could map that using middleware, but you'd need to know more specific details about the actions going through and it seems like more "execution-related" code. But then it doesn't need to know anything about the state. It just needs to decide which actions to forward on to the reducers.

So? Would such code go in a reducer or in middleware? And can anyone provide other specific examples that clarify the difference between the two?


Solution

  • A reducer is a function that takes some part of your state and the current dispatched action as arguments, and returns an updated state. Multiple reducer functions can be composed together to form your root reducer function that you pass to createStore(). Reducers are supposed to be "pure functions", with no "side effects". That means no AJAX calls, no dispatching actions, and (in theory) no logging - just (state, action) => newState. (Now, you can do logging in a reducer, and that code will work fine, but as a matter of principle that's still not something a reducer is supposed to do.)

    A middleware is a piece of code that wraps around the store's dispatch function. Multiple middlewares can be turned into a pipeline through the applyMiddleware() enhancer. When an action is dispatched, it will be passed through each middleware in the pipeline in turn. Each middleware can do whatever it wants with the action: log it, delay it, modify it, dispatch something else instead, or just pass it onwards down the pipeline. Eventually, the last middleware passes the action on to the actual store.dispatch() function, which calls the root reducer and starts the state update logic.

    So yes, in general, middleware provide a place to perform centralized logic related to actions, such as authorization checks or logging.

    You may want to read the Structuring Reducers section in the Redux docs for more examples of how reducers work and can be organized, and my React/Redux links list has sections of articles discussing Redux middleware and reducer usage.