2

欢迎关注redux源码分析系列文章:
redux源码分析之一:createStore.js
redux源码分析之二:combineReducers.js
redux源码分析之三:bindActionCreators.js
redux源码分析之四:compose.js
redux源码分析之五:applyMiddleware

combineReducers.js文件对外暴露了一个函数combineReducers,combineReducer函数是redux的一个辅助性的函数,用于拆分createStore里面的第一个参数:reducer函数。combineReducer函数的返回值是一个函数,该函数是组合之后的一个标准的reducer函数。

一、分析combineReducers函数的参数:

combineReducers函数仅包含一个参数reducers,reducers是一个object类型参数,比如:

let reducers = {
    users: function getUsersReducer(){}, 
    userInfo: function getUserInfoReducer(){}
}

二、分析combineReducers返回之前做了什么:

1、从传入的参数里面提取出合法的reducers(reducers的每一个key对应的value值是函数,才是合法的子reducer),赋值给新的局部变量:finalReducers

  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}"`)
      }
    }
    //过滤出reducers对应的value值是function的key,将其放入finalReducers对象
    if (typeof reducers[key] === 'function') {
      finalReducers[key] = reducers[key]
    }
  }

2、校验finalReducers, 判断其每一个子reducer是否能返回正常的子state

  //取出过滤出来的有效的keys列表
  const finalReducerKeys = Object.keys(finalReducers)

  let unexpectedKeyCache
  if (process.env.NODE_ENV !== 'production') {
    unexpectedKeyCache = {}
  }

  let shapeAssertionError
  try {
    assertReducerShape(finalReducers)
  } catch (e) {
    shapeAssertionError = e
  }

assertReducerShape函数:

//确认reducer是否是合法的reducer,即返回的state是不是undefined,如果是undefined,则是非法reducer
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.`
      )
    }

    const type = '@@redux/PROBE_UNKNOWN_ACTION_' + Math.random().toString(36).substring(7).split('').join('.')
    if (typeof reducer(undefined, {type}) === '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.`
      )
    }
  })
}

三、分析combineReducers函数的返回值:

函数combination是一个标准的reducer函数,有初始化的state参数,和一个携带了actionType和数据的action对象。

function combination(state = {}, action) {
    //如果有非法的reducer,就直接报错喽
    if (shapeAssertionError) {
      throw shapeAssertionError
    }

    if (process.env.NODE_ENV !== 'production') {
      const warningMessage = getUnexpectedStateShapeWarningMessage(state, finalReducers, action, unexpectedKeyCache)
      if (warningMessage) {
        warning(warningMessage)
      }
    }

    let hasChanged = false
    //定义新的nextState
    const nextState = {}
    // 1,遍历reducers对象中的有效key,
    // 2,执行该key对应的value函数,即子reducer函数,并得到对应的state对象,即子state
    // 3,将新的子state挂到新的nextState对象上,key不变
    for (let i = 0; i < finalReducerKeys.length; i++) {
      const key = finalReducerKeys[i]
      const reducer = finalReducers[key]
      const previousStateForKey = state[key]
      const nextStateForKey = reducer(previousStateForKey, action)
      if (typeof nextStateForKey === 'undefined') {
        const errorMessage = getUndefinedStateErrorMessage(key, action)
        throw new Error(errorMessage)
      }
      nextState[key] = nextStateForKey
      //如果hasChanged为true,那就是true了   后面的判断是,只要有一次nextStateForKey!== previousStateForKey不同,就说明整个state不同
      hasChanged = hasChanged || nextStateForKey !== previousStateForKey
    }
    //如果state发生变化了,直接返回新的nextState,否则,还是返回旧的state
    return hasChanged ? nextState : state
  }
}

四、总结:

combineReducers函数其实就实现一个功能:将一个复杂的父reducer函数,根据state状态对应的key,拆分成几个子reducer;每个子reducer返回一个子state。多层嵌套的reducer树,可以对应组成一个多层嵌套的state状态树。

完整解析请参考我的github:https://github.com/abczhijia/...,如果对您有帮助,欢迎star,有任何问题也请指正。


Happi
244 声望6 粉丝