Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Issues with higher order store with compose(..., createStore) #376

Closed
taylorhakes opened this issue Jul 31, 2015 · 1 comment
Closed

Issues with higher order store with compose(..., createStore) #376

taylorhakes opened this issue Jul 31, 2015 · 1 comment

Comments

@taylorhakes
Copy link
Contributor

In the redux-devtools and several other example repos, Redux higher order stores have been implemented in the following way

const finalCreateStore = compose(
  applyMiddleware(thunk),
  devTools(),
  persistState(window.location.href.match(/[?&]debug_session=([^&]+)\b/)),
  createStore
);

For those unfamiliar, the code does essentially the following

// Returns a function
middleware(devtools(persistState(createStore)))

All the functions have the following structure

function higherOrderStore(next) {
  return (reducer, initialState) => {

    // manipulate reducer if needed

    const store = next(manipulatedReducer, initialStore);

    // manipulate the store if needed

     return {
      ...store,
      // store overrides
    };
  };

It is generally a great API because it is simple, easy to understand and functional. Unfortunately, this API also has a major downside. It is not possible wrap store.dispatch and reducer when the user uses multiple higher order stores.

With compose the first function gets the first opportunity to receive reducer and wrap it in some way, but is the last to get store.dispatch. If you look at the above code, the higher order store is calling next(manipulatedReducer, initialStore).

This means reducer moves middleware -> devtools -> persistedState -> createStore. and store.dispatch moves middlewares <- devtools <-persistedState <- createStore. There is an issue when multiple higher order stores wrap the store.dispatch and the reducer.

For instance, devtools wraps all actions with extra data in the store.dispatch and then unwraps the action in the reducer. If another HOS wants to do the same thing, it is not possible because the wrapping and unwrapping needs to be in the same order. For example, if the HOS that is the last store to wrap the action and store.dispatcher, it needs to be the last store to wrap the reducer so it has the correct view of the actions entering the reducer.

The previous example shows that compose makes the store.dispatch and reducer wrapping go in opposite directions and that is an issue. I ran into this issue while implementing pseudo local state. In order to work around it, I have to turn the reducer into a weird dispatcher. That is definitely not the best solution.

https://github.com/taylorhakes/redux-devtools/blob/local-global-state/examples/todomvc/LocalState.js

I don't know the best solution to this, but one option would be to pass store instead of createStore to HOSs.

const store = createStore(reducer);
middleware(devtools(persistState(store)));

That would depend on a change to the store API exposing the reducer. This following issue may help.
#350

@gaearon
Copy link
Contributor

gaearon commented Aug 14, 2015

Let's continue this discussion in #350. There's some discussion there already, and I'd like to consolidate it, as these problems will be solved together. (But thanks a lot for writing this up!)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants