在redux
項目開發(fā)過程中扛伍,有時候我們需要自己去編寫一些redux
中間件稚伍, 但是中間件用法法一般都像下面這樣子:
export function myMidware ({dispatch, getState}) {
// 返回一個接收dispatch為參數(shù)的函數(shù)
return (dispatch) => (action) => {
// do something
return dispatch(action)
}
}
//使用中間件
const store = createStore(reducer, applyMiddleware(myMidware))
一看到這種套娃的寫法间校,整個人都是懵的枯途。那么接下來我就帶著問題給大家理解理解, 為什么中間件函數(shù)非要這么寫, applyMiddleware
究竟做了什么
廢話不多說首先來看看applyMiddleware
的源碼杀狡,看看它到底做了啥:
// 首先這個函數(shù)接收多個中間件函數(shù)颜骤,放在middlewares的數(shù)組中
export default function applyMiddleware(...middlewares) {
// 返回一個接受createStore參數(shù)的函數(shù), 這個函數(shù)執(zhí)行之后應(yīng)該返回一個增強版createStore函數(shù)
// (...args) => { ... } 這里可以看成是一個增強版的createStore函數(shù)(從createStore源碼可以看出)
return createStore => (...args) => {
const store = createStore(...args)
// 這里的dispatch是不希望你在創(chuàng)建中間件的時候調(diào)用它
let dispatch = () => {
throw new Error(
'Dispatching while constructing your middleware is not allowed. ' +
'Other middleware would not be applied to this dispatch.'
)
}
// 把原版store的api構(gòu)造成對象準(zhǔn)備傳遞給中間件
const middlewareAPI = {
getState: store.getState,
dispatch: (...args) => dispatch(...args) // 個人感覺這里不給用 其實就沒必要給到中間件構(gòu)造函數(shù)里面去
}
// 把構(gòu)造好的api對象傳遞給中間件捣卤,讓中間件擁有可以訪問store的能力
const chain = middlewares.map(middleware => middleware(middlewareAPI))
// compose函數(shù)可以把多個中間件函數(shù)的數(shù)組,合成一個中間件函數(shù)的形式八孝,然后再執(zhí)行中間件
// 并將得到的新的函數(shù) 當(dāng)作新的dispatch函數(shù)
dispatch = compose(...chain)(store.dispatch)
// 返回一個增強了dispatch函數(shù)的store
return {
...store,
dispatch
}
}
}
從上面的代碼解讀可以看出董朝, applyMiddleware
函數(shù),做了已下事情:
- 返回一個新的
createStore
函數(shù)干跛,這里叫它superCreateStore
函數(shù) - 在
supterCreateStore
函數(shù)中子姜,執(zhí)行了createStore
函數(shù),可見args
其實就是reducer
楼入,看createStore
函數(shù)源碼可知傳入的就是reducer
-
superCreateStore
函數(shù)中執(zhí)行中間件函數(shù)哥捕,得到了一個新的dispatch
函數(shù),這里叫它superDispatch
- 最后
supterCreateStore
函數(shù)返回了一個新的store
對象嘉熊,這個對象改造了dispatch
函數(shù)
看完了源碼遥赚,接下來就開始理解這個思路了,套娃開始:
首先是applyMiddleware
-
createStore( reducer, enhancer)
返回一個store
-
applyMiddleware(...middleWares)
返回enhancer
增強器 -
enhencer
就是一個函數(shù)阐肤,接收createStore
為參數(shù)凫佛,返回一個superCreateStore
函數(shù) -
superCreateStore
函數(shù)和createStore
一樣讲坎,接手reducers
作為參數(shù),返回一個新的store
再來理解中間件函數(shù)執(zhí)行過程
- 在
superCreateStore
中愧薛,第一次執(zhí)行中間傳入了middlewareAPI
, 得到了dispatch
增強器 -
dispatch
增強器通過compose組合后晨炕,還是個dispatch增強器,再執(zhí)行傳入store.dispatch毫炉,也就是store原本的dispatch
函數(shù)作為參數(shù) 得到了superDispatch
函數(shù)
到此我們就已經(jīng)完全理解了中間件的執(zhí)行過程及其作用瓮栗,其實就是返回了一個
dispatch
增強器函數(shù)的函數(shù),得到的增強器函數(shù)接收dispatch
返回一個新的dispatch
函數(shù)瞄勾,dispatch
執(zhí)行后會返回action
费奸,就是這樣的邏輯, 這樣我們就可以在action
被dispatch
到store
之前丰榴,做一些處理货邓。
compose
函數(shù)正是一個鏈?zhǔn)秸{(diào)用dispatch
增強器的函數(shù),每次執(zhí)行一個函數(shù)都會返回一個增強過的dispatch
函數(shù)四濒,給下一個中間件换况, 下面貼一下compose
函數(shù)的代碼, 感興趣的可以理解一下:
export default function compose(...funcs) {
if (funcs.length === 0) {
return arg => arg
}
if (funcs.length === 1) {
return funcs[0]
}
// 這里的args就是dispatch
return funcs.reduce((a, b) => (...args) => a(b(...args)))
}