Redux: Allow to alter state in middleware

Created on 18 May 2016  路  10Comments  路  Source: reduxjs/redux

Hi, thanks for redux, it's awesome!

I've just published a reducer allows to update the state using the path to the updated value in meta and the updated value in payload's action:

const store = createStore((state = defaultState, action) => {
    const nextState = updateImmutableState(state, action);
    // Operate with nextState here
    return nextState;
});

store.dispatch({
    type: 'updateElementInObject',
    meta: ['bar', 'boo'],
    payload: {
        boo: 1
    }
});

This is very powerful when used in combination with tcomb-form-native or tcomb-form.

I would like to implement middleware functionality so it could be just _plugged-in_ and forget calling the path-reducer inside the app reducer. It would be a kind of node middleware where you can alter the req/res and call next middleware. I've been thinking on how it could be implemented, and right now I've found a solution but there are two features that needs to be implemented in redux:

  /**
   * Reads the reducer currently used by the store to calculate the state.
   *
   * You might need this if your app implements code splitting and you want to
   * load some of the reducers dynamically.
   *
   * @returns {Function} The reducer the store is currently using.
   */
  function getReducer() {
    return currentReducer
  }
    var middlewareAPI = {
      getState: store.getState,
      dispatch: (action) => dispatch(action),
      getReducer: store.getReducer,
      dispatch: store.replaceReducer
    }

If there is no better approach, I could do a PR implementing these features. I'm writting this issue instead of opening a PR to have an opinion if there is a better way to achieve it.

discussion

Most helpful comment

Sure, this works well!

All 10 comments

I've just published a reducer allows to update the state using the path to the updated value in meta and the updated value in payload's action:

This negates the benefits of Redux because you鈥檙e effectively moving the knowledge about the state shape outside reducers. If you like this pattern, you don鈥檛 need to use Redux at all鈥攋ust use cursor support in ImmutableJS.

you鈥檙e effectively moving the knowledge about the state shape outside reducers

Totally agree with you. There are two separate things here:

  1. The implementation of the functionality that middleware is able to modify state (node-express middleware style)
  2. The implementation of a path-reducer

The first case I'm trying to imagine the benefits, if there could be more plugins that could take advantadge of this feature vs the inconvenients which I can't see right now.

This negates the benefits of Redux

The second case I'm going to explain my situation: I'm creating an app that saves the tcomb-form-native data in a branch of the state tree, and uses redux for other situations. In this way I can keep all the app the data in the same logic with the advantadges of updating the part of the state that I know the path. I could use separate patterns, but would mean to maintain separate structures. In this way I can mantain only one pattern, namely, redux and keep the app simpler.

I think middleware is not the right approach for this. What you currently have (a reducer provided by the library) looks like the correct approach. What issues do you have with it?

It seemed to me that this functionality is more a middleware approach than an _in reducer call_, maybe because I was comparing with node-express like cookie parser, body parser, etc. Probably you're right and this implementation is good enought for the purpose.

On the other hand, allowing to modify the state in the middleware of redux it seemed to me like opening a door for people to write maybe who knows useful plugins for redux (like path-reducer 馃槃)

It is a very important constraint in Redux that the state only changes inside a reducer. This makes time travel possible. So we definitely don鈥檛 want to add such capabilities to the middleware.

Just for a better clarification. I'm not understanding what does it mean:

This makes time travel possible

Why is this so important and why mutating the state in middleware could break this? Could you provide an example for the situation that could be a problem?

@miqmago https://code-cartoons.com/hot-reloading-and-time-travel-debugging-what-are-they-3c8ed2812f35
In short, all changes to the state are recorded as action (the plain-data actions), and can be reproduced to any extent by the devtool, and thus changes can be "time traveled" through.

Why is this so important

Capabilities like time travel and hot reloading were the original reason Redux was created. Redux DevTools would break if you modified state elsewhere. It is also not just about time travel鈥攚e have found that the same constraints that enable time travel also enable other cool things (e.g. pluggable optimistic actions, or recording and replaying actions for reproducing bug reports) so we use that as a guiding principle. This was one of the reasons Redux became popular in the first place 馃槈 .

Thanks! That gave me an idea to make it work. Let me know your opinion please. I could write a wrapper like this:

const pathReducer = (reducer) => (state, action) => {
    const nextState = updateImmutableState(state, action);
    return reducer(nextState, action);
};

const store = createStore(pathReducer(reducer));

Sure, this works well!

Was this page helpful?
0 / 5 - 0 ratings

Related issues

ramakay picture ramakay  路  3Comments

vraa picture vraa  路  3Comments

mickeyreiss-visor picture mickeyreiss-visor  路  3Comments

ms88privat picture ms88privat  路  3Comments

parallelthought picture parallelthought  路  3Comments