Search code examples
javascriptreduxredux-middleware

Why Redux middleware defined as three arrow functions instead of a single function with three arguments?


Why do we do this:

const middleware = store => next => action => { ... }

and not something simpler like

const middleware = (store, next, action) => { ... }

Was there some advantage to the Redux team for designing middleware this way? Is there some functionality we can take advantage of if we split up the middleware functions?

In my own applications I've defined a simplerMiddleware() function that can convert from the second form to the first and it seems to work well.

function simpleMiddleware(simpleMiddlewareFunction) {
  return store => next => action => simpleMiddlewareFunction(store, next, action);
}

Why the three arrow functions?

Note: I'm not asking what is currying or why currying exists in functional programming or what are the generic benefits of currying; was there a specific reason the Redux designers chose this signature over a simpler three argument function?


Solution

  • This is specifically addressed in the Redux FAQ entry on "why does the middleware signature use currying?":

    Redux middleware are written using a triply-nested function structure that looks like const middleware = storeAPI => next => action => {}, rather than a single function that looks like const middleware = (storeAPI, next, action) => {}. There's a few reasons for this.

    One is that "currying" functions is a standard functional programming technique, and Redux was explicitly intended to use functional programming principles in its design. Another is that currying functions creates closures where you can declare variables that exist for the lifetime of the middleware (which could be considered a functional equivalent to instance variables that exist for the lifetime of a class instance). Finally, it's simply the approach that was chosen when Redux was initially designed.

    The curried function signature of declaring middleware is deemed unnecessary by some, because both store and next are available when the applyMiddleware function is executed. This issue has been determined to not be worth introducing breaking changes, as there are now hundreds of middleware in the Redux ecosystem that rely on the existing middleware definition.