redux源碼學習筆記 - combineReducers

上一篇有了解到,reducer函數的兩個爲:當前state和這次dispatch的action。html

state的結構是JavaScript對象,每一個key均可以表明着不一樣意義的數據。好比說redux

{
        lists:object,
        type:string
    }

lists管理列表數據,type管理選中的類型。此時就須要考慮將state分爲不一樣的子樹,每次子樹數據對應一個reducer子函數,單獨管理對應的state。可是createStore(reducer,preloadedState)函數接收的reducer必須爲單一個函數。這個時候就須要用到combinReducers函數,它的做用是把多個reducer函數合併成一個最終的reducer函數數據結構

combineReducers(reducers)

看一下combineReducers函數實現的核心代碼,如下代碼刪掉了異常提示和處理部分,只保留了關鍵部分。async

export default function combineReducers(reducers) {
  //過濾掉參數中,value不是function的
  const reducerKeys = Object.keys(reducers)
  const finalReducers = {}
  for (let i = 0; i < reducerKeys.length; i++) {
    const key = reducerKeys[i]

    if (typeof reducers[key] === 'function') {
      finalReducers[key] = reducers[key]
    }
  }
  // 處理後的reducers對象的全部key值
  const finalReducerKeys = Object.keys(finalReducers)

  // 返回合併後的reducer函數,她接收的參數和普通的reducer函數一致。
  // 這裏的state是完整的數據結構,而單一的reducer函數接收的只是它管理的那個子樹
  return function combination(state = {}, action) {

    let hasChanged = false
    const nextState = {}
    // 有action分派時,對全部的子reducer都觸發
    // 由於action有type字段,因此仍是會觸發到對應的之reducer函數
    for (let i = 0; i < finalReducerKeys.length; i++) {
      const key = finalReducerKeys[i]
      const reducer = finalReducers[key]
      // 對應的子樹數據
      const previousStateForKey = state[key]
      // 調用對應的reduer函數,返回子樹數據的更新結果
      const nextStateForKey = reducer(previousStateForKey, action)
      
      // 子樹數據同步到state中
      nextState[key] = nextStateForKey
      // 標記數據是否發生變化,只要有一個子樹改變了就算數據已改變
      hasChanged = hasChanged || nextStateForKey !== previousStateForKey
    }
    // 返回state數據
    return hasChanged ? nextState : state
  }
}

combineReducers接收的reducers是value爲子reducer函數的對象。對象的key值能夠和函數名一致,也能夠不一樣。返回的state的key值和reducers對象的key值是保持一致的。函數

因此當createStore(reducer,preloadedState)中的reducer函數是combineReducers合併成的,傳入初始狀態時,要注意state的keys要和reducers一致spa

可見combineReducers主要的功能,就是把action傳入到全部的子reducer函數遍歷一次,同時處理state的切片和合並code

固然這裏少了不少異常校驗部分的代碼,有興趣能夠查閱詳細源碼。htm

實例

/* reducer */
import {combineReducers} from 'redux';
import testAsync from './testasync';
import todoList from './todolist';

const reducer = combineReducers({
    testAsync,
    todoList
});

export default reducer;

/* store */
import {createStore} from 'redux';
import reducer from './reducer/index';

let store = createStore(reducer)

{testAsync,todoList}便是reducer函數對象,key和函數名同樣。{a:testAsync,b:todoList}寫成這樣也能夠。對象

state的獲取,更新和單一的reducer函數同樣,上一篇已作過介紹。blog

相關文章
相關標籤/搜索