在大型项目中将代码拆分为多个按需加载的js包,redux中也可以实现动态添加reducer到store,可以使用replaceReducer
:
该函数使用新的 root reducer
替代当前活动的 root reducer
。调用该函数将替换内部 reducer 的引用,并 dispatch
一个 action
以初始化新加入的 reducer
:
const newRootReducer = combineReducers({
existingSlice: existingSliceReducer,
newSlice: newSliceReducer
})
store.replaceReducer(newRootReducer)
我们可能想从应用程序的任何地方调用 store.replaceReducer()
。因此,它使我们可以很轻易的定义一个可重用的 injectReducer()
函数。该函数能够保持对所有现有 slice reducer
的引用,并可将新 reducer
附加到 store
实例。
下面是injectReducer
使用的两种方法,路过的大佬可以帮忙对比一下两种方案:
import { createStore } from 'redux'
// 定义将始终存在于应用程序中的 Reducer
const staticReducers = {
users: usersReducer,
posts: postsReducer
}
// Configure the store
export default function configureStore(initialState) {
const store = createStore(createReducer(), initialState)
// 添加一个对象以跟踪已注册的异步 Reducer
store.asyncReducers = {}
//创建注入 reducer 函数
// 此函数添加 async reducer,并创建一个新的组合 reducer
store.injectReducer = (key, asyncReducer) => {
store.asyncReducers[key] = asyncReducer
store.replaceReducer(createReducer(this.asyncReducers))
}
// 返回修改后的 store
return store
}
function createReducer(asyncReducers) {
return combineReducers({
...staticReducers,
...asyncReducers
})
}
现在,只需要调用 store.injectReducer 函数即可向 store 添加新的 reducer。
import React from 'react';
import _ from 'lodash';
import PropTypes from 'prop-types';
import hoistNonReactStatics from 'hoist-non-react-statics';
import getInjectors from './reducerInjectors';
/**
* Dynamically injects a reducer
*
* @param {string} key A key of the reducer
* @param {function} reducer A reducer that will be injected
*
*/
export default ({ key, reducer }) => (WrappedComponent) => {
class ReducerInjector extends React.Component {
static WrappedComponent = WrappedComponent;
static contextTypes = {
store: PropTypes.object.isRequired,
};
static displayName = `withReducer(${WrappedComponent.displayName ||
WrappedComponent.name ||
'Component'})`;
injectors = getInjectors(_.get(this.context, 'store'));
componentWillMount() {
const { injectReducer } = this.injectors;
injectReducer(key, reducer);
}
render() {
return <WrappedComponent {...this.props} />;
}
}
return hoistNonReactStatics(ReducerInjector, WrappedComponent);
};
reducerInjectors.js
import createReducer from 'js/redux/reducers';
export function injectReducerFactory(store) {
return function injectReducer(key, reducer) {
// Check `store.injectedReducers[key] === reducer` for hot reloading when a key is the same but a reducer is different
if (
Reflect.has(store.injectedReducers, key) &&
store.injectedReducers[key] === reducer
) {
return;
}
store.injectedReducers[key] = reducer; // eslint-disable-line no-param-reassign
store.replaceReducer(createReducer(store.injectedReducers));
};
}
export default function getInjectors(store) {
return {
injectReducer: injectReducerFactory(store),
};
}
关于Reflect和hoist-non-react-statics的具体用法可以参考链接。