Redux: middleware - Why currying rather than (store, action, next) ->

Created on 15 Aug 2015  ·  7Comments  ·  Source: reduxjs/redux

Hi, the new docs are great. One question I had while reading the whole middleware section is why does the middleware has to be curried? Why not simply:

var store = <..>;
store.addMiddleware(function(store, action, next) {
  var result = next();
  // whatever
});

Maybe a quick point explaining in the doc would be helpful.

docs question

Most helpful comment

Thanks for the question. I was starting to question my understanding of the middleware lesson by believing that the currying was absolutely necessary :smile:

All 7 comments

Could be both actually ramda works that way.

Sometimes we want to associate some local state with store and next, like in rAF scheduler from middleware docs:

const rafScheduler = store => next => {
  let queuedActions = [];
  let frame = null;

  function loop() {
    frame = null;
    try {
      if (queuedActions.length) {
        next(queuedActions.shift());
      }
    } finally {
      maybeRaf();
    }
  }

  function maybeRaf() {
    if (queuedActions.length && !frame) {
      frame = requestAnimationFrame(loop);
    }
  }

  return action => {
    if (!action.meta || !action.meta.raf) {
      return next(action);
    }

    queuedActions.push(action);
    maybeRaf();

    return function cancel() {
      queuedActions = queuedActions.filter(a => a !== action)
    };
  };
};

We could have made it (store, next) => action => () but I don't see a problem with just going all the way. You might want some configuration later, at which point options => (store, next) => action => () looks kinda arbitrary.

Honestly when I read the docs, specifically this line:

But there’s also a different way to enable chaining. The middleware could accept the next() dispatch function as a parameter instead of reading it from the store instance.

I had _expected_ the following:

function logger(store, next) {]
  return function dispatchAndLog(action) {
    console.log('dispatching', action);
    let result = next(action);
    console.log('next state', store.getState());
    return result;
  };
}

But was instead:

function logger(store) {
  return function wrapDispatchToAddLogging(next) {
    return function dispatchAndLog(action) {
      console.log('dispatching', action);
      let result = next(action);
      console.log('next state', store.getState());
      return result;
    };
  }
}

I guess I am not satisfied with "I don't see a problem with just going all the way." To me, the problem is that it is neednessly complicated. The call to this in applyMiddleware

dispatch = middleware(store)(dispatch)

could simply be

dispatch = middleware(store, dispatch)

This also deviates from express' middleware signature: (req, res, next) => void. It isn't (req, res) => next => void.

To me, the problem is that it is neednessly complicated.

Is

store => next => action => yourcode

more complicated to write than

(store, next) => action => yourcode

?

I understand your concerns, maybe you're right. Maybe it breaks some use case we haven't considered. I don't know. But this feedback would have been more useful at the time middleware was designed (it was all publicly discussed: #55). Right now there is a lot of middleware in the ecosystem that uses the current signature, and unless you see a way to change it in backwards-compatible way, I don't think “remove store =>” is a reason compelling enough to break everyone.

Thanks for the question. I was starting to question my understanding of the middleware lesson by believing that the currying was absolutely necessary :smile:

I think that since the redux expectation of the function is this signature

const middleware = store => next => action => {
    // do something
}

then you can write your middleware curried version as follows:

_.curry((store, next, action) => {
   // do something
})

then redux being calling middleware(store)(next)(action) will work with the curried version.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

jimbolla picture jimbolla  ·  3Comments

elado picture elado  ·  3Comments

CellOcean picture CellOcean  ·  3Comments

rui-ktei picture rui-ktei  ·  3Comments

cloudfroster picture cloudfroster  ·  3Comments