combineReducer

对于将多个reducer合并为一个的做法,redux为我们提供了一个方便的API叫combineReducer ,同样,为了搞懂它到底是怎么运作的,我们可以尝试实现它。

在之前的例子里,我们注意到最后返回的reducer的key与子reducer同名,所以函数内部过程应该是:

  1. 向combineReducer传入一个对象,假设我们有子reducer A,B, 那么我们这样传入: combineReducer({A, B}) ,它的对等形式就是: combineReducer({A: A, B: B}),这是ES6的语法糖 - Destructing Assignment.
  2. 获取key数组
  3. 以这个key数组为数据,获取一个合并后的reducer 函数
/**
* combineReducer => merge all reducer function into one
* @param [Object] reducers object, { reducerVaribale, ... }
* @return [function] mixed reducer function
*/

const combineReducer = (reducers) => {
  return (state = {}, action) => { // return a reduce function
    return Object.keys(reducers).reduce(
      (nextState, key) => {  // When gave an initial value(here is {}), nextState will be {}
        nextState[key] = reducers[key](state[key], action)
        // This is actually very similar to 'todos: todos(state.todos, action)' in todos reducer
        return nextState
      }, 
      {} //initial value => offered a container for mixed state
    )
  }
}

OK,我们把其中最麻烦的一部分拿出来分析:

Object.keys(reducers).reduce(
 (nextState, key) => {
    nextState[key] = reducers[key](state[key], action)
    return nextState
    },
  {} //initial value => offered a container for mixed state
)

我们假设{ReducerA, ReducerB}是参数reducers:

  1. Object.keys(reducers) => ['ReducerA', 'ReducerB']
  2. ['ReducerA', 'ReducerB'].reduce()
  3. 我们把里面的函数提取出来: function (accumulator, currentValue) { }
  4. 如果我们不给定reduce函数一个initialValue, 那么初始状态下accumulator会是第一个key,显然,我们的操作对象不是key,而是一个对象,这个对象将包含所有的state.
  5. 给定initialValue{} ,接上面第三步,函数体:accumulator[currentValue] = reducers[currentValue](state[currentValue], action)
  6. 手动跑reduce结果:
    1. Initial State 对应关系: accumulator = {} , currentValue = 'ReducerA'
      1. {}['ReducerA'] = ReducerA(state['ReducerA],action) 此时state['ReducerA]undefined ,前面解释过,ReducerA 自带默认state ,会正常返回值.
    2. Second State 对应关系: accumulator = { 'ReducerA' : ReducerA返回的state } , currentValue = 'ReducerB

现在清晰了吗? 最后的返回结果便会是{ 'ReducerA' : ReducerA返回的state, 'ReducerB' : ReducerB返回的state }

测试一下我们的函数是否可用:

It works !

results matching ""

    No results matching ""