在《React高級篇(一)從Flux到Redux下硕,react-redux》文章中貼過一張redux單向數(shù)據(jù)流的圖海渊,但是角撞,從action到reduer,其實還缺少了不少環(huán)節(jié)褥民。
舉個例子季春,如果發(fā)起一個異步動作(比如網(wǎng)絡(luò)請求),該如何處理消返?redux單向數(shù)據(jù)流一定是同步的载弄,碰上異步Action耘拇,必須將其轉(zhuǎn)為同步Action,才可以繼續(xù)走下去宇攻,否則事件會被丟失惫叛。
再比如,如果需要給每個Action都要打Log逞刷,那么嘉涌,是否有個節(jié)點可以統(tǒng)一處理?
于是亲桥,store enhance(middleware是它的特殊實現(xiàn))出現(xiàn)了洛心,Action到達reducer之前固耘,會經(jīng)過一系列的enhancer處理看下圖:
復(fù)習(xí):Store的創(chuàng)建方式
createStore(reducer, [preloadedState], [enhancer])
第三個參數(shù)即是enhancer
题篷。
創(chuàng)建Store的enhancer
一個store對象中包含下列接口:
- dispatch
- subscribe
- getState
- replaceReducer
一般來說,自定義enhancer都是針對上述接口做能力增強厅目,比如提供日志功能的logEnhancer番枚,定義如下:
const logEnhancer = (createStore) => (reducer, preloadedState, enhancer) => (
const store= createStore(reducer, preloadedState, enhancer);
const originalDispatch = store.dispatch;
store.dispatch = (action) => {
console.log('dispatch action:’,action);
originalDispatch(action);
return store;
};
增強器通常都使用這樣的模式损敷,將store上某個函數(shù)的引用存下來葫笼,給這個函數(shù)一個新的實現(xiàn),但是在完成增強功能之后拗馒,還是要調(diào)用原有的函數(shù)路星,保持原有的功能。
store enhancer和middleware的關(guān)系诱桂?
middleware本身就是一個store enhancer洋丐,它專門負(fù)責(zé)增強redux.dispatch()
方法。middleware源碼示意如下:
export default function middleware(...middlewares) {
return createStore => (...args) =>
{ // 省略 return { ...store, dispatch }
}
}
注意:middleware應(yīng)該置于enhancer隊列的最前排挥等。
分發(fā)一個action時友绝,middleware通過next(action)一層層處理和傳遞action到Redux原生的dispatch。
如果某個middleware使用store.dispatch(action))分發(fā)action肝劲,會跳出middleware管道迁客,重新再來。如下圖:
store.dispatch(action)的應(yīng)用場景
action默認(rèn)都是同步的辞槐。如果是一個異步Action(異步請求)掷漱,那么需要一個專門處理異步請求的middleware,這是會用到store.dispatch()榄檬。這樣卜范,異步工作流才可以被所有中間件處理,否則丙号,它只能被當(dāng)前位置之后的中間件處理先朦。
常用的異步流中間件處理庫為redux-thunk缰冤。
const thunk = store =>next => action =>
typeof action === 'function' ? action(store.dispatch, store.getState) : next(action)
異步Acton設(shè)計如下:發(fā)起異步請求,如果成功喳魏,彈出成功彈框棉浸,否則,彈出錯誤彈框刺彩。
const getThenShow = (dispatch, getState) =>{
const url = 'http://xxx.json';
fetch(url)
.then(response=>{
dispatch({
type: 'SHOW_MESSAGE_SUCCESS',
message: response.json
})
})
.catch(error=>{
dispatch({
type: 'SHOW_MESSAGE_FAIL',
message: 'error'
})
})
}
后記
講redux-thunk相關(guān)的文章非常多迷郑,不再累述。
參考文章:淺析Redux 的 store enhancer创倔,書籍-《深入淺出react和redux》