reduxjs / redux

A JS library for predictable global state management
https://redux.js.org
MIT License
60.88k stars 15.27k forks source link

Working with multiple redux objects #247

Closed volkanunsal closed 9 years ago

volkanunsal commented 9 years ago

I'm using Redux in a small library that will be used within a larger app that has its own redux object. My problem is I need to find a way to manage both of them together, since the library needs to subscribe to the state of the host as well as its own state.

Currently, I have a very crude solution around juggling these two objects separately within the library –– and perhaps merging the two –– but I'd like to figure out a more refined solution for managing multiple redux objects, if at all possible.

What might be your recommendations for approaching this problem?

Thank you.

acdlite commented 9 years ago

You should use a higher-order store. These are like higher-order components in React. We're working hard to improve the documentation on this pattern. Here's an initial version explaining how they work.

https://github.com/gaearon/redux/blob/improve-docs/docs/higher-order-stores.md

I'll link to the improved docs once they're finished :)

acdlite commented 9 years ago

You can also take a sneak peak at the Redux DevTools which @gaearon has started moving over to the new API. It's a great example of a higher-order store. https://github.com/gaearon/redux/blob/finalize-devtools/examples/counter/redux-devtools/index.js#L200-L207

volkanunsal commented 9 years ago

Hm, sounds intriguing, and it could totally be useful. But I'm not sure how to use it within the existing workflow. This may be something the documentation might address. In particular, I'm wondering what it will mean in terms of creating the redux object.

The documentation mentions a short way and a long way of creating the redux object, and I've been using the short way with createRedux.

import React from 'react';
import Map from './Map';
import { createRedux } from 'redux';
import { Provider } from 'redux/react';
import * as reducers from '../reducers';

export default class App {
  render() {
    const redux = createRedux(reducers);
    return (
      <Provider redux={redux}>
        {() => <Map />}
      </Provider>
    );
  }
}

If I were to compose my stores before creating the redux, I'd probably need to do this...

import React from 'react';
import Map from './Map';
import { createRedux, createDispatcher, composeStores } from 'redux';
import thunkMiddleware from 'redux/lib/middleware/thunk';
import { Provider } from 'redux/react';
import * as reducers from '../reducers';

export default class App {
  render() {
    // Host redux
    let state = this.props.redux.getState();
    const store = composeStores(Object.assign(reducers, state));
    const dispatcher = createDispatcher(
      store,
      getState => [thunkMiddleware(getState)] 
    );
    const redux = createRedux(dispatcher);

    return (
      <Provider redux={redux}>
        {() => <Map />}
      </Provider>
    );
  }
}

Correct me if I'm wrong....

gaearon commented 9 years ago

Both examples are slightly wrong because you're creating redux inside render(). That's an anti-pattern. (Can we enforce that?)

gaearon commented 9 years ago

@volkanunsal Can you describe your use case in a little more detail? You said there's an outer app, but there's also a library, and you want to have two Reduxes. Why can't the root library component accept dispatch and state as props? This way, it won't have to manage its own state, and will delegate to the app. Your library can even export a reducer so the app can import it and mount somewhere in its state tree.

volkanunsal commented 9 years ago

That's a great idea! I think I might end up doing that.