Following is the approach that I have followed to implement this.
We have our store file where we will have static reducers who will always be present in the reducer, and dynamic reducers will be added when required component is mounted.
reducer file
The staticReducers that will always be present in the application
const staticReducers = combineReducers({
entities1: entities1,
});
const createReducer = (asyncReducers) => {
return combineReducers({
staticReducers,
...asyncReducers,
});
};
export default createReducer;
store file
Here we can have our custom middleware, loggers etc, those we can pass in the middlewares array.and use it as follows.
import { createStore, applyMiddleware, compose } from "redux";
import createReducer from "./reducers";
import api from "./middlewares/api";
const middlewares = [ api, thunkMiddleware]
const middlewareEnhancer = applyMiddleware(...middlewares)
const enhancers = [middlewareEnhancer]
const composedEnhancers = composeWithDevTools(compose(...enhancers))
const store = createStore(createReducer(), composedEnhancers)
export default function configureStore() {
// Add a dictionary to keep track of the registered async reducers
store.asyncReducers = {};
// Create an inject reducer function
// This function adds the async reducer, and creates a new combined
// reducer
store.injectReducer = (key, asyncReducer) => {
store.asyncReducers[key] = asyncReducer;
store.replaceReducer(createReducer(store.asyncReducers));
};
// Return the modified store
return store;
}
export function getStore() {
return store;
}
Now suppose we have a component that we want to load dynamically and that component might have its own slice(reducer), then we can call inject reducer to dynamically add its to the existing reducer.
const Counter2 = React.lazy(() =>
import("../counter2/counter2").then(async (module) => {
const entities2 = await
import("../../../store/entities2").then((todosModule) =>
todosModule.default);
store.injectReducer("entities2", entities2);
return module;
})
)
<React.Suspense fallback={<div>loading...</div>}>
<Counter2 />
</React.Suspense>
After mounting this component we will find entities2 injected to our store.