redux源碼學習筆記 - applyMiddleware

在建立store時,createStore(reducer, preloadedState, enhancer),除了reducer函數,初始狀態,還能夠傳入enhancer。這個enhancer在createStore的源碼中是這樣使用的redux

return enhancer(createStore)(reducer, preloadedState)

它能夠接受createStore方法並進行自定義改裝,而後再使用改裝後的方法建立倉庫。app

而redux官方提供的enhancer就只有applyMiddleware函數

applyMiddleware(...middlewares)

applyMiddleware的主要功能是改寫createStore中的dispatch方法,而且能夠將多個middleware組合到一塊兒,形式鏈式的調用,先後互不影響。這樣要求middleware必須遵循必定的格式。({ getState, dispatch }) => next => action => {}this

applyMiddleware的實現

export default function applyMiddleware(...middlewares) {
  // 返回一個enhancer函數,接受createStore做爲參數(能夠對照enhancer的調用方式來看)
  return createStore => (...args) => { // enhancer函數接受reducer, preloadedState來建立倉庫
    const store = createStore(...args)
    // 自定義dispatch函數,在構造middleware的時候,不容許調用dispatch
    let dispatch = () => {
      throw new Error(
        `Dispatching while constructing your middleware is not allowed. ` +
          `Other middleware would not be applied to this dispatch.`
      )
    }

    const middlewareAPI = {
      getState: store.getState, // store中的getState函數,用於獲取狀態
      dispatch: (...args) => dispatch(...args) // 自定義的dispatch函數
    }
    // 傳入到getState,和dispatch到middleware中 生成 next => action => {} 格式的函數
    const chain = middlewares.map(middleware => middleware(middlewareAPI))

    // 自定義的dispatch更新爲 多個middleware的組合函數;傳入store本來dispatch函數給組合函數(會在最後一個middle中做爲next函數)
    dispatch = compose(...chain)(store.dispatch)

    // 返回store倉庫,此時的dispatch函數已被改寫,爲多個middleware的組合函數
    return {
      ...store,
      dispatch
    }
  }
}

組合和鏈式調用

關鍵是要理解這裏dispatch = compose(...chain)(store.dispatch),dispatch被改寫爲多個middleware的組合函數。spa

compose函數中關鍵的一句是return funcs.reduce((a, b) => (...args) => a(b(...args)))code

a能夠理解爲next => action => {},而next能夠理解爲b(...args) 就是下一個middleware的 ation => {} 函數。因此實現了鏈式調用。a中作了自定義的操做,會調用b,b調用c···最後一個調用store.dispatchblog

用兩個middleware作例子來梳理改寫後的dispatch(action)的調用過程。get

自定義middleware

middleware必須遵循必定的格式。({ getState, dispatch }) => next => action => {}源碼

{getState, dispatch}參數是在applyMiddleware的源碼中const chain = middlewares.map(middleware => middleware(middlewareAPI))這一部分被傳入的,store的getState和改寫後的dispatch。io

next是下一個middleware或者store.dispatch,action是觸發的動做

/*logger*/
export default ({dispatch,getState}) => next => action => {
    // 作一些自定義的事情
    console.log('will dispatch ation',action);
    console.log('next in loggere',next);

    // 調用下一個middleware
    let returnValue = next(action);

    console.log('state after dispatch',getState());

    return returnValue;
}
/*test*/
export default ({dispatch,getState}) => next => action => {
        
    console.log('next in  test',next)

    return next(action);
}

使用applyMiddleware

store = createStore(reducer,applyMiddleware(logger,test))

觸發action時,有以下打印

logger作完自定義操做後,調用下一個middleware(test)函數,test是最後一個middleware,它的next是store.dispatch,就觸發了action。

相關文章
相關標籤/搜索