-
Star
(103)
You must be signed in to star a gist -
Fork
(8)
You must be signed in to fork a gist
-
-
Save gaearon/eeee2f619620ab7b55673a4ee2bf8400 to your computer and use it in GitHub Desktop.
| import React, { Component } from 'react' | |
| import Subapp from './subapp/Root' | |
| class BigApp extends Component { | |
| render() { | |
| return ( | |
| <div> | |
| <Subapp /> | |
| <Subapp /> | |
| <Subapp /> | |
| </div> | |
| ) | |
| } | |
| } | |
| // These subapps will be completely independent. | |
| // | |
| // They won't share data or actions, and won't see or communicate with each other. | |
| // If you mix this approach with standard Redux approach of composing reducers, it | |
| // will get extremely confusing so it's best if you pick just one: either your app | |
| // is composed of pieces that follow Redux pattern holistically, or your app is so | |
| // large and disjointed that smaller independent "subapps" make more sense. | |
| // | |
| // The first case is probably closer to normal web products, and the second case is | |
| // closer to a "product hub", a "dashboard", or enterprise software where unrelated | |
| // tools are grouped together because they're part of one package. |
| // This is our subapp's root connected component. | |
| // It can render more components, connected or not, below, just like normally. | |
| // Usually we'd render it in <Provider> and be done with it. | |
| class App extends Component { ... } | |
| export default connect(mapStateToProps)(App) |
| // However we don't have to call ReactDOM.render(<Provider><App /></Provider>) | |
| // if we're interested in hiding the fact that it's a Redux app. | |
| // | |
| // Maybe we want to be able to run multiple instances of it in the same "bigger" app | |
| // and keep it as a complete black box, with Redux being an implementation detail. | |
| // To hide Redux behind a React API, we can wrap it in a special component that | |
| // initializes the store in the constructor. This way every instance will be independent. | |
| // | |
| // Note that this is *not* recommended for parts of the same app that share data. | |
| // But it can be useful when the bigger app has zero access to smaller apps' internals, | |
| // and we'd like to keep the fact that they are implemented with Redux an implementation detail. | |
| // Each component instance will have its own store, so they won't "know" about each other. | |
| import React, { Component } from 'react' | |
| import { Provider } from 'react-redux' | |
| import reducer from './reducers' | |
| import App from './App' | |
| class Root extends Component { | |
| constructor(props) { | |
| super(props) | |
| this.store = createStore(reducer) | |
| } | |
| render() { | |
| return ( | |
| <Provider store={this.store}> | |
| <App /> | |
| </Provider> | |
| ) | |
| } | |
| } |
@jochakovsky I think in that case I will use createProvider and your own connect for <SubApp/>. <SubApp/> container will be taking selected props and actions from <BigApp/> connect and from your sub-store with a custom one.
For example (pseudocode):
import { Provider, connect } from 'react-redux';
const coreStore = createStore(coreReducers);
const SubProvider = createProvider('sub');
const subStore = createStore(subReducers);
const SubAppContainer = compose(
withSubStore('sub')(mapSubStoreStateToProps, mapSubStoreDispatchToProps),
connect(mapStateToProps, mapDispatchToProps),
)(subAppView);
<Provider store={coreStore}>
<Router>
<Route path='/sub'> // I assume that your SubApp will be loaded dynamically on route change
<SubProvider store={subStore}>
<SubAppContainer/>
</SubProvider>
</Route>
</Router>
</Provider>
@jochakovsky I think in that case I will use
createProviderand your ownconnectfor<SubApp/>.<SubApp/>container will be taking selected props and actions from<BigApp/>connect and from your sub-store with a custom one.
For example (pseudocode):import { Provider, connect } from 'react-redux'; const coreStore = createStore(coreReducers); const SubProvider = createProvider('sub'); const subStore = createStore(subReducers); const SubAppContainer = compose( withSubStore('sub')(mapSubStoreStateToProps, mapSubStoreDispatchToProps), connect(mapStateToProps, mapDispatchToProps), )(subAppView); <Provider store={coreStore}> <Router> <Route path='/sub'> // I assume that your SubApp will be loaded dynamically on route change <SubProvider store={subStore}> <SubAppContainer/> </SubProvider> </Route> </Router> </Provider>
the annoyance of using this method is that in the official redux documentation states - "You probably only need this if you are in the inadvisable position of having multiple stores".
Thanks for this nice Gist! But I wonder how to
dispatchactions to the component's own special store? Is there a way to access thestore-prop of the<Provider />for each<SubApp />(and their child-components)?
Has anyone figured this out yet?
I am using react to build components for a WordPress site. Each 'root' component will need its own state, but how would I use useDispatch and useSelector to get each component's appropriate state?
@Nathaniel-Fernandes @gaearon any advice with dispatching scoped actions?
How about using a subApp as a child of another subApp like this?
return(
<SubApp1>
<SubApp2/>
</SubApp1>
)
Suppose the SupApp2 is a calendar app or something which should be used inside of SubApp1, but there are no shared components between these 2 subApps.
Is it possible?
Having a similar problem to @ghernandez345 and @tylerwgoza, my
<Subapp />s need to accept props from<BigApp />, any thoughts on how to handle that elegantly? I described my problem a bit more here: https://stackoverflow.com/questions/49082353/whats-the-best-way-to-call-callbacks-passed-into-a-redux-subapp