From 11d85769d0b1ea11d2c991394eedc8bfd9935b2e Mon Sep 17 00:00:00 2001 From: jero Date: Sat, 21 Sep 2019 20:47:35 +0300 Subject: [PATCH] feat(store): create dynoStore adds the ability to code-splitting reducers in order to use them when needed BREAKING CHANGE: initial store is replace by dynoStore improves #32 --- src/app/store/config/configureStore.js | 1 + src/app/store/config/dynoStore/dynoStore.js | 64 +++++++++++++++++++ src/app/store/config/dynoStore/index.js | 4 ++ .../store/config/dynoStore/reduceReducers.js | 13 ++++ src/app/store/config/enhancers/index.js | 21 ++++++ 5 files changed, 103 insertions(+) create mode 100644 src/app/store/config/dynoStore/dynoStore.js create mode 100644 src/app/store/config/dynoStore/index.js create mode 100644 src/app/store/config/dynoStore/reduceReducers.js create mode 100644 src/app/store/config/enhancers/index.js diff --git a/src/app/store/config/configureStore.js b/src/app/store/config/configureStore.js index e20110f1..fe047df5 100644 --- a/src/app/store/config/configureStore.js +++ b/src/app/store/config/configureStore.js @@ -32,6 +32,7 @@ function configureStore() { const store = createStore<{}, Actions, Dispatch>( reducer, // persistedState, + // $FlowFixMe composeEnhancers(applyMiddleware(...middlewares)), // third parameter is called an 'enhancer' ); /* // Save the state any time the store state changes diff --git a/src/app/store/config/dynoStore/dynoStore.js b/src/app/store/config/dynoStore/dynoStore.js new file mode 100644 index 00000000..d3682e96 --- /dev/null +++ b/src/app/store/config/dynoStore/dynoStore.js @@ -0,0 +1,64 @@ +/* eslint-disable implicit-arrow-linebreak */ +// @flow strict +import { + createStore as createReduxStore, + combineReducers, +} from 'redux'; +import type { Dispatch } from 'redux'; + +// import type { State } from '@/store/types/State'; +import type { Actions } from '@/store/types/Actions'; + +import reduceReducers from './reduceReducers'; + +let store = {}; +const reducerMap = {}; + +// $FlowFixMe +const injectReducers = (_reducerMap): void => { + Object.entries(_reducerMap).forEach(([name, reducer]) => { + if (!reducerMap[name]) { + reducerMap[name] = []; + } + reducerMap[name].push(reducer); + }); +}; + +const createRootReducer = () => ( + // $FlowFixMe + combineReducers(Object.keys(reducerMap).reduce((result, key) => ({ + ...result, + [key]: reduceReducers(reducerMap[key]), + }), {})) +); + +// $FlowFixMe +const createStore = (...args) => { + store = createReduxStore<{}, Actions, Dispatch>(createRootReducer(), ...args); + return store; +}; + +const reloadStore = (): void => { + store.replaceReducer(createRootReducer()); + // store.dispatch({ type: '@@replace-reducer' }); +}; + +export const dynoStore = { + injectReducers, + createRootReducer, + createStore, + reloadStore, +}; + +export const withReloadStore = (importPromise: *): Promise<*> => ( + importPromise + .then((module) => { + dynoStore.reloadStore(); + return module; + }, + (error) => { + throw error; + }) +); + +export default dynoStore; diff --git a/src/app/store/config/dynoStore/index.js b/src/app/store/config/dynoStore/index.js new file mode 100644 index 00000000..0b39c280 --- /dev/null +++ b/src/app/store/config/dynoStore/index.js @@ -0,0 +1,4 @@ +// @flow strict + +// eslint-disable-next-line import/prefer-default-export +export { default as dynoStore } from './dynoStore'; diff --git a/src/app/store/config/dynoStore/reduceReducers.js b/src/app/store/config/dynoStore/reduceReducers.js new file mode 100644 index 00000000..7b1eea9b --- /dev/null +++ b/src/app/store/config/dynoStore/reduceReducers.js @@ -0,0 +1,13 @@ +// @flow strict +import type { State } from '@/store/types/State'; +import type { Actions } from '@/store/types/Actions'; + +type ReducersType = Array<($Shape, Actions) => {}>; + +const reduceReducers = (reducers: ReducersType) => (state: State, action: Actions) => ( + reducers.reduce((result, reducer) => ( + reducer(result, action) + ), state) +); + +export default reduceReducers; diff --git a/src/app/store/config/enhancers/index.js b/src/app/store/config/enhancers/index.js new file mode 100644 index 00000000..5b933e70 --- /dev/null +++ b/src/app/store/config/enhancers/index.js @@ -0,0 +1,21 @@ +// @flow strict +import { compose, applyMiddleware } from 'redux'; +import type { Dispatch, StoreEnhancer } from 'redux'; + +import middlewares from '@/store/config/middlewares'; + +import type { State } from '@/store/types/State'; +import type { Actions } from '@/store/types/Actions'; + +type EnhancersType = StoreEnhancer> +/* eslint-disable */ +const devtools = + typeof window !== 'undefined' && + typeof window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ === 'function' && + window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__({ actionsBlacklist: [] }); + /* eslint-enable */ +const composeEnhancers = devtools || compose; +// eslint-disable-next-line no-underscore-dangle +const enhancer: EnhancersType = composeEnhancers(applyMiddleware(...middlewares)); + +export default enhancer;