redux源碼學習筆記 - applyMiddleware
在創建store時,createStore(reducer, preloadedState, enhancer)
,除了reducer函數,初始狀態,還可以傳入enhancer
。這個enhancer在createStore的源碼中是這樣使用的
return enhancer(createStore)(reducer, preloadedState)
它可以接受createStore方法並進行自定義改裝,然後再使用改裝後的方法創建倉庫。
而redux官方提供的enhancer就只有applyMiddleware
。
applyMiddleware(...middlewares)
applyMiddleware的主要功能是改寫createStore中的dispatch
({ 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