redux源碼分析之二:combineReducers.js

歡迎關注redux源碼分析系列文章:
redux源碼分析之一:createStore.js
redux源碼分析之二:combineReducers.js
redux源碼分析之三:bindActionCreators.js
redux源碼分析之四:compose.js
redux源碼分析之五:applyMiddlewaregit

combineReducers.js文件對外暴露了一個函數combineReducers,combineReducer函數是redux的一個輔助性的函數,用於拆分createStore裏面的第一個參數:reducer函數。combineReducer函數的返回值是一個函數,該函數是組合以後的一個標準的reducer函數。github

1、分析combineReducers函數的參數:

combineReducers函數僅包含一個參數reducers,reducers是一個object類型參數,好比:redux

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

2、分析combineReducers返回以前作了什麼:

一、從傳入的參數裏面提取出合法的reducers(reducers的每個key對應的value值是函數,纔是合法的子reducer),賦值給新的局部變量:finalReducerssegmentfault

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]
    }
  }

二、校驗finalReducers, 判斷其每個子reducer是否能返回正常的子stateapp

//取出過濾出來的有效的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函數:less

//確認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.`
      )
    }
  })
}

3、分析combineReducers函數的返回值:

函數combination是一個標準的reducer函數,有初始化的state參數,和一個攜帶了actionType和數據的action對象。dom

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
  }
}

4、總結:

combineReducers函數其實就實現一個功能:將一個複雜的父reducer函數,根據state狀態對應的key,拆分紅幾個子reducer;每一個子reducer返回一個子state。多層嵌套的reducer樹,能夠對應組成一個多層嵌套的state狀態樹。ide

完整解析請參考個人github:https://github.com/abczhijia/...,若是對您有幫助,歡迎star,有任何問題也請指正。函數

相關文章
相關標籤/搜索