reducer 动态注入

2019-09-30  本文已影响0人  Mr君

在大型项目中将代码拆分为多个按需加载的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的具体用法可以参考链接。

上一篇下一篇

猜你喜欢

热点阅读