1. 程式人生 > >Redux原始碼解讀(二)

Redux原始碼解讀(二)

上篇文章我們分析了createStore和combineReducers檔案,這一篇我們分析剩下的檔案。

首先是bindActionCreators檔案,這個檔案十分簡單

function bindActionCreator(actionCreator, dispatch) {
  return function() {
    return dispatch(actionCreator.apply(this, arguments))
  }
}

上面的高階函式是在檔案內部中使用,這個是為了減少重複程式碼,返回的函式中的引數傳給的actionCreator函式執行,然後dispatch將其返回值作為引數再執行,其返回值作為該函式的返回值。

export default function bindActionCreators(actionCreators, dispatch) {
  if (typeof actionCreators === 'function') {
    return bindActionCreator(actionCreators, dispatch)
  }

  if (typeof actionCreators !== 'object' || actionCreators === null) {
    throw new Error(
      `bindActionCreators expected an object or a function, instead received 
${ actionCreators === null ? 'null' : typeof actionCreators }. ` + `Did you write "import ActionCreators from" instead of "import * as ActionCreators from"?` ) } const keys = Object.keys(actionCreators) const boundActionCreators = {} for (let i = 0; i < keys.length
; i++) { const key = keys[i] const actionCreator = actionCreators[key] if (typeof actionCreator === 'function') { boundActionCreators[key] = bindActionCreator(actionCreator, dispatch) } } return boundActionCreators }

這個函式很簡單,其中第一個引數既可以是函式也可以是物件,如果是函式,則直接返回bindActionCreator處理後的函式,若為物件,則通過迴圈其key值遞迴找到每一個對應的ActionCreator,最後返回一個相應的物件。

也就是說,如果輸入的是函式,則返回的是函式,若輸入的是物件,則返回的也是物件。

接下來我們看compose檔案(其實這個檔案只是一個工具函式)

export default function compose(...funcs) {
  if (funcs.length === 0) {
    return arg => arg
  }

  if (funcs.length === 1) {
    return funcs[0]
  }

  return funcs.reduce((a, b) => (...args) => a(b(...args)))
}

當compose引數為空時,則返回一個函式,該函式直接返回其引數

若引數為一個時,則直接返回該引數(該引數應當是一個函式)

若引數為多個時,則通過reduce進行累計,返回一個函式,該函式內部是一層一層函式的疊加,該函式引數在疊加的最內層呼叫。舉個栗子�

compose(f, g, h)就意味著
返回(...args) => f(g(h(...args)))

而compose函式在applyMiddleware中被使用

export default function applyMiddleware(...middlewares) {
  return createStore => (...args) => {
    const store = createStore(...args)
    let dispatch = () => {
      throw new Error(
        `Dispatching while constructing your middleware is not allowed. ` +
          `Other middleware would not be applied to this dispatch.`
      )
    }
    let chain = []

    const middlewareAPI = {
      getState: store.getState,
      dispatch: (...args) => dispatch(...args)
    }
    chain = middlewares.map(middleware => middleware(middlewareAPI))
    dispatch = compose(...chain)(store.dispatch)

    return {
      ...store,
      dispatch
    }
  }
}

該函式接收多個函式作為引數,然後返回一個函式,該函式又返回一個函式(說真的不喜歡這樣的千層餅。。。),而這個函式則返回解散的store和dispatch

在最內層的函式立刻,首先通過createSotre建立了一個store,然後定義了一個奇葩版的dispatch,也就是說在使用中介軟體裡嚴禁呼叫dispatch

然後通過map將state和奇葩版的dispatch傳入中介軟體,最後通過compose將其dispatch作為千層餅最內層被中介軟體一層一層的裹起來,這樣日後呼叫dispatch就必然會呼叫一層一層的中介軟體。(dispatch的結果作為引數),最後將這些值作為返回值

最後是我自己寫的一個超簡易版redux,功能不及正版redux強大,但勝在簡單,有興趣的朋友可以看一下

diaotai/myreduxgithub.com圖示

redux的內容在redux資料夾內,clone後npm install最後npm start即可