redux源碼解讀(二)

以前,已經寫過一篇redux源碼解讀(一),主要分析了 redux 的核心思想,並用100多行代碼實現一個簡單的 redux 。可是,那個實現還不具有合併 reducer 和添加 middleware 的功能。git

今天咱們一塊兒來看看合併 reducer (即 combineReducers) 的原理和實現。github

在分析原理以前,先來看看combineReducers 的用法:redux

import { createStore, combineReducers } from 'redux';
const addScore = (state, action) => {};
const deleteScore = (state, action) => {};
const rootReducer = combineReducers({addStore, deleteScore});
const store = createStore(rootReducer);

從上面的例子能夠看出,combineReducers 接收的參數類型是一個原生對象,其中這個對象的每一個鍵值都是一個 reducer 純函數。另外,由於 combineReducer() 返回的結果能夠傳遞給createStore做爲參數,能夠推出它返回的結果也是一個 reducer 函數。函數

瞭解了 combineReducer 用法以後 ,那開始一步一步的用代碼來實現其功能吧。prototype

首先,須要先聲明 combineReducers 的參數,而後判斷傳進來的參數是否是原生對象類型( plain object ),若是不是,則拋出異常,若是是,則須要獲取該對象的全部屬性(key)並存放到變量 reducerKeys 裏面,而後對這些key進行遍歷,過濾掉那些不是函數的值,並將結果放到 finalReducerKeys 裏面。代碼以下:code

export default function combineReducers(reducers) {
  // 判斷參數reducers是否爲對象
  if(Object.prototype.toString.call(reducer) !== '[object Object]') {
    throw new Error('combineReducers expected plain object params');
  }

  const reducerKeys = Object.keys(reducers);
  let finalReducerKeys = [];
  // 過濾掉value不是Function類型的鍵名,而後將結果放到fianlReducerKeys裏面
  reducerKeys.forEach((key, i) => {
    if(typeof reducers[key] === 'function') {
      finalReducerKeys.push(key);
    }
  });
}

前面已經提到過了 combineReducers 返回的結果是一個純函數。那這個返回的函數須要處理些什麼邏輯呢?由於他合併了其餘的 reducers,因此須要遍歷這些 reducer 並執行他們。而後,並對比一下執行 reducer 以後的數據有沒有變化 ,若是有變化則返回新的 state, 不然直接返回以前的 state。代碼以下:對象

export default function combineReducers(reducers) {
  // 省略和前面相同的部分

  // 返回一個新的、通過組合的reducer函數
  return function(state = {}, action) {
    let hasChanged = false;
    const nextState = {};
    // 遍歷finalReducerKeys,並調用對應的reducer。
    finalReducerKeys.forEach((key, i) => {
      const stateForKey = state[key];
      const nextStateForKey = reducers[key](stateForKey, action);
      nextState[key] = nextStateForKey;
      // 若是先後狀態不同,則hasChanged設爲true
      if(stateForKey !== nextStateForKey) {
        hasChanged = true;
      }
    });
    // 若是有變化,則返回新的state,不然返回舊的
    return hasChanged ? nextState : state;
  }
}

OK,《redux 源碼解讀(二)》就寫到這裏,今天週五啦,祝你們週末愉快哈!若是對 combineReducer還有不明白的地方,歡迎留言討論哈。另外,可能有些地方我分析得不到位的,建議到個人github去下載代碼本身再好好研究一下。重要的事情說三遍:代碼在這裏下載! 代碼在這裏下載! 代碼在這裏下載!blog

相關文章
相關標籤/搜索