1. 程式人生 > >redux源碼學習筆記 - applyMiddleware

redux源碼學習筆記 - applyMiddleware

state 動作 area ogg this 圖片 let .com while

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

    return enhancer(createStore)(reducer, preloadedState)

它可以接受createStore方法並進行自定義改裝,然後再使用改裝後的方法創建倉庫。

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

applyMiddleware(...middlewares)

applyMiddleware的主要功能是改寫createStore中的dispatch

方法,並且可以將多個middleware組合到一起,形式鏈式的調用,前後互不影響。這樣要求middleware必須遵循一定的格式。({ getState, dispatch }) => next => action => {}

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的組合函數。

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

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

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

自定義middleware

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

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

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。

redux源碼學習筆記 - applyMiddleware