Redux 源码解读之 combineReducers


combineReducers 源码地址:node_modules/redux/src/combineReducers.js。
combineReducers 的核心功能是为了使业务逻辑能够更加颗粒化,用户可以设计多个 reducer,而 combineReducers 就可以对这些 reducer 进行合并。

一、深复制一份 reducers

 const reducerKeys = Object.keys(reducers)
  const finalReducers = {}
  for (let i = 0; i < reducerKeys.length; i++) {
    const key = reducerKeys[i]
    if (process.env.NODE_ENV !== 'production') {
      if (typeof reducers[key] === 'undefined') {
        warning(`No reducer provided for key "${key}"`)
      }
    }
    if (typeof reducers[key] === 'function') {
      finalReducers[key] = reducers[key]
    }
  }
  const finalReducerKeys = Object.keys(finalReducers)

reducers 是 combineReducers 方法的参数,该参数是一个键值对对象。以上源码中,首先获取对象的键值数组,然后循坏其数组,并将每一个键值对赋值给 finalReducers。以此实现将所有的 reducers 深度复制给 finalReducers。同时获取新的 finalReducers 键值对数组 finalReducerKeys 。

二、断言每一个 reducer

 let unexpectedKeyCache
  if (process.env.NODE_ENV !== 'production') {
    unexpectedKeyCache = {}
  }
  let shapeAssertionError
  try {
    assertReducerShape(finalReducers)
  } catch (e) {
    shapeAssertionError = e
  }
  

通过 assertReducerShape 方法对新的 finalReducers 断言。

 function assertReducerShape(reducers) {
  Object.keys(reducers).forEach(key => {
    const reducer = reducers[key]
    const initialState = reducer(undefined, { type: ActionTypes.INIT })
    if (typeof initialState === 'undefined') {
      throw new Error(
        `Reducer "${key}" returned undefined during initialization. ` +
          `If the state passed to the reducer is undefined, you must ` +
          `explicitly return the initial state. The initial state may ` +
          `not be undefined. If you don't want to set a value for this reducer, ` +
          `you can use null instead of undefined.`
      )
    }
    if (
      typeof reducer(undefined, {
        type: ActionTypes.PROBE_UNKNOWN_ACTION()
      }) === 'undefined'
    ) {
      throw new Error(
        `Reducer "${key}" returned undefined when probed with a random type. ` +
          `Don't try to handle ${
            ActionTypes.INIT
          } or other actions in "redux/*" ` +
          `namespace. They are considered private. Instead, you must return the ` +
          `current state for any unknown actions, unless it is undefined, ` +
          `in which case you must return the initial state, regardless of the ` +
          `action type. The initial state may not be undefined, but can be null.`
      )
    }
  })
}

对每一个 reducer 传一个初始的 type, 判断其返回值是否是 undefined ,如果是 undefined ,则 创建 Error 对象。也就是报错提示。

三、对比新旧 state

  return function combination(state, action) {
    if (state === void 0) {
      state = {};
    }
    if (shapeAssertionError) {
      throw shapeAssertionError;
    }
    if (process.env.NODE_ENV !== 'production') {
      var warningMessage = getUnexpectedStateShapeWarningMessage(state, finalReducers, action, unexpectedKeyCache);
      if (warningMessage) {
        warning(warningMessage);
      }
    }
    var hasChanged = false;
    var nextState = {};
    for (var _i = 0; _i < finalReducerKeys.length; _i++) {
      var _key = finalReducerKeys[_i];
      var reducer = finalReducers[_key];
      var previousStateForKey = state[_key];
      var nextStateForKey = reducer(previousStateForKey, action);
      if (typeof nextStateForKey === 'undefined') {
        var errorMessage = getUndefinedStateErrorMessage(_key, action);
        throw new Error(errorMessage);
      }
      nextState[_key] = nextStateForKey;
      hasChanged = hasChanged || nextStateForKey !== previousStateForKey;
    }
    return hasChanged ? nextState : state;
  };

combineReducers 方法返回了一个闭包函数,这个闭包函数接收传入的 state 和action。

  1. 如果 state 为 undefined,即 void 0,state 重置为 空对象 {}。
  2. 如果有断言错误,捕捉错误。
  3. 将变量 hasChanged 初始为 false,下一个 state ,即 nextState 初始化为 空对象 {}。
  4. 取出finalReducers 中所有的 key 和 value(也就是每一个 reducer),获取当前 reducer 作用后的 state,将当前 state 和 action 作为参数获取下一个 state 。
  5. 对 hasChanged 重新赋值,如果 下一个 state 和当前 state 不相等,hasChanged 为 true,否则为 false。
  6. hasChanged 为 true 时,返回下一个 state,否则返回当前传入的 state。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值