-
回顧redux
- redux解決了什么問題
- redux基本架構(gòu)圖
- dispatch函數(shù)
-
如何編寫中間件
- 中間件函數(shù)基本格式
- 中間件洋蔥模型
-
redux中間件源碼解析
- applyMiddleware函數(shù)
- compose函數(shù)
1. 回顧redux
-
redux解決了什么問題
-
一個react應(yīng)用就是一顆組件樹,react是單向數(shù)據(jù)流。單向數(shù)據(jù)流的情況下,組件之間數(shù)據(jù)如何通信?組件的公共數(shù)據(jù)應(yīng)該放在哪里?
redux.png
-
-
redux基本架構(gòu)圖

0_cntBtPADjE2ykLSP.png
-
dispatch函數(shù)

redux-diagram.jpg
2. 如何編寫redux中間件
- 中間件函數(shù)本質(zhì)就是對dispatch方法的擴展,那么如何優(yōu)雅的擴展dispatch方法?
- mid1,mid2,mid3分別為三個中間件函數(shù),編寫中間件函數(shù)有一個固定格式,必須按照以下格式編寫
// getState獲取當前state的狀態(tài)
function mid1({ getState }) {
// next指向下一個要執(zhí)行的(action) => {}匿名函數(shù)
return (next) => {
// action是指dispatch中的對象
return (action) => {
console.log('start mid1')
next(action)
console.log('end mid1');
}
}
}
// getState獲取當前state的狀態(tài)
function mid2({ getState }) {
// next指向下一個要執(zhí)行的(action) => {}匿名函數(shù)
return (next) => {
// action是指dispatch中的對象
return (action) => {
console.log('start mid2')
next(action)
console.log('end mid2');
}
}
}
// getState獲取當前state的狀態(tài)
function mid3({ getState }) {
// next指向下一個要執(zhí)行的(action) => {}匿名函數(shù)
return (next) => {
// action是指dispatch中的對象
return (action) => {
console.log('start mid3')
next(action)
console.log('getState() :', getState());
console.log('end mid3');
}
}
}
// 配置中間件
const middleware = [mid1, mid2, mid3]
// 創(chuàng)建store
const finalCreateStore = applyMiddleware(...middleware)(createStore)
-
觸發(fā)一次dispatch后的執(zhí)行結(jié)果
WechatIMG95log.jpeg -
中間件洋蔥模型
-
當用戶調(diào)用dispatch時,首先執(zhí)行mid1中間件,在mid1中調(diào)用next執(zhí)行mid2中間件,依次執(zhí)行,最終調(diào)用dispatch,dispatch調(diào)用結(jié)束后,依次執(zhí)行剩余中間件代碼。
zIjmUzn.png
3. redux中間件源碼解析
// 配置中間件
const middleware = [mid1, mid2, mid3]
// 創(chuàng)建store
const finalCreateStore = applyMiddleware(...middleware)(createStore)
-
applyMiddleware函數(shù)
function applyMiddleware(...middlewares) {
// createStore創(chuàng)建store調(diào)用的方法
return createStore => (...args) => {
const store = createStore(...args)
const chain = middlewares.map(middleware => middleware())
/*
chain: [
f1: (next) => (action) => { console.log('start mid1'); next(action); console.log('end mid1'); },
f2: (next) => (action) => { console.log('start mid2'); next(action); console.log('end mid2'); },
f3: (next) => (action) => { console.log('start mid3'); next(action); console.log('end mid3'); }
]
*/
dispatch = compose(...chain)(store.dispatch)
/*
dispatch = f1(f2(f3(store.dispatch)))
*/
return {
...store,
dispatch
}
}
}
-
compose
// (f1, f2, f3) -> (...args) => f1(f2(f3(...args)))
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)))
}


