在《React高级篇(一)从Flux到Redux,react-redux》文章中贴过一张redux单向数据流的图,但是,从action到reduer,其实还缺少了不少环节。
举个例子,如果发起一个异步动作(比如网络请求),该如何处理?redux单向数据流一定是同步的,碰上异步Action,必须将其转为同步Action,才可以继续走下去,否则事件会被丢失。
再比如,如果需要给每个Action都要打Log,那么,是否有个节点可以统一处理?
于是,store enhance(middleware是它的特殊实现)出现了,Action到达reducer之前,会经过一系列的enhancer处理看下图:
复习:Store的创建方式
createStore(reducer, [preloadedState], [enhancer])
第三个参数即是enhancer
。
创建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上某个函数的引用存下来,给这个函数一个新的实现,但是在完成增强功能之后,还是要调用原有的函数,保持原有的功能。
store enhancer和middleware的关系?
middleware本身就是一个store enhancer,它专门负责增强redux.dispatch()
方法。middleware源码示意如下:
export default function middleware(...middlewares) {
return createStore => (...args) =>
{ // 省略 return { ...store, dispatch }
}
}
注意:middleware应该置于enhancer队列的最前排。
分发一个action时,middleware通过next(action)一层层处理和传递action到Redux原生的dispatch。
如果某个middleware使用store.dispatch(action))分发action,会跳出middleware管道,重新再来。如下图:
store.dispatch(action)的应用场景
action默认都是同步的。如果是一个异步Action(异步请求),那么需要一个专门处理异步请求的middleware,这是会用到store.dispatch()。这样,异步工作流才可以被所有中间件处理,否则,它只能被当前位置之后的中间件处理。
常用的异步流中间件处理库为redux-thunk。
const thunk = store =>next => action =>
typeof action === 'function' ? action(store.dispatch, store.getState) : next(action)
异步Acton设计如下:发起异步请求,如果成功,弹出成功弹框,否则,弹出错误弹框。
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相关的文章非常多,不再累述。
参考文章:浅析Redux 的 store enhancer,书籍-《深入浅出react和redux》