redux-injectable-store
Version:
Redux store with injectable reducers for use with bundle splitting, large apps, and SPAs.
66 lines (55 loc) • 1.81 kB
JavaScript
import { createStore, combineReducers } from 'redux';
import warning from 'warning';
const FAKE_INITIAL_REDUCER_NAMESPACE = '___';
const IDENTITY_REDUCER = (state = null) => state;
const defaultWrapReducer = reducer => reducer;
const makeEmptyReducerMap = () => ({
// putting this here because `combineReducers` will complain if there isn't at least
// one reducer initially.
[FAKE_INITIAL_REDUCER_NAMESPACE]: IDENTITY_REDUCER,
});
const createInjectableStore = (preloadedState, enhancer, wrapReducer = defaultWrapReducer) => {
let reducers = makeEmptyReducerMap();
const store = createStore(wrapReducer(combineReducers(reducers)), preloadedState, enhancer);
const replace = () => {
store.replaceReducer(wrapReducer(combineReducers(reducers)));
};
const clearReducers = () => {
reducers = makeEmptyReducerMap();
};
const inject = (namespace, reducer, force = false) => {
if (reducers[namespace] != null && !force) {
warning(
false,
`Attempted to inject a new reducer in an already existing namespace ('${namespace}') without \`force\`. Skipping.`
);
return;
}
reducers[namespace] = reducer;
replace();
};
const injectAll = (reducerMap, force = false) => {
let hasChanged = false;
Object.keys(reducerMap).forEach(namespace => {
if (reducers[namespace] != null && !force) {
warning(
false,
'Attempted to inject a new reducer in an already existing namespace without `force`. Skipping.'
);
return;
}
reducers[namespace] = reducerMap[namespace];
hasChanged = true;
});
if (hasChanged) {
replace();
}
};
return {
...store,
inject,
injectAll,
clearReducers,
};
};
module.exports = createInjectableStore;