最近在看redux-saga源码,发现它最后也返回标准的Redux中间件格式,之前在解析react-redux中有稍微带到,不过还是有些茫然,现在这部分再梳理下,在这里做个理解。
使用中间件
以日志输出中间件为例
import { applyMiddleware, createStore } from 'redux';
import createLogger from 'redux-logger';
const logger = createLogger();
const store = createStore(
reducer,
applyMiddleware(logger)
);
logger 中间件简码
function createLogger(options = {}) {
····
return store => next => (action) => {
·····
let returnedValue;
returnedValue = next(action);
return returnedValue;
};
}
看的出来返回的格式就是 store => next => action =>{} 三层嵌套,接下来我们再把这些拆解下。
applyMiddleware
在之前的文章中,咱们稍微分析了下applyMiddleware,这里再稍微回顾下
1. export default function applyMiddleware(...middlewares) {
2. return createStore => (...args) => {
3. // 创建store
4. const store = createStore(...args)
5. // 新建变量 dispatch 函数
6. let dispatch = () => {
7. throw new Error(
8. 'Dispatching while constructing your middleware is not allowed. ' +
9. 'Other middleware would not be applied to this dispatch.'
10. )
11. }
12.
13. const middlewareAPI = {
14. getState: store.getState,
15. dispatch: (...args) => dispatch(...args)
16. }
17. // 把 store.getState 和 dispatch 注入到每个中间件
18. const chain = middlewares.map(middleware => middleware(middlewareAPI))
19. // 调用compose, 重新赋值经过中间件扩展后的dispatch
20. dispatch = compose(...chain)(store.dispatch)
21. // 返回 store, 扩展后的dispatch
22. return {
23. ...store,
24. dispatch
25. }
26. }
27. }
解析三层函数
可以看到从最外层开始看,store就是 middlewareAPI,也就是 getState和 dispatch,
const chain = middlewares.map(middleware => middleware(middlewareAPI))
那么chain就是剩下的两层 next => action =>{},我们看到第20行,
dispatch = compose(...chain)(store.dispatch)
这里chain被当做参数传入compose。compose的作用其实就是循环调用中间件,之前的文章中也较少过,其实效果就是下面一样
const func = [f1, f2, f3];
compose(...func) //return f1(f2(f3(...args)))
//注意函数调用的顺序是从左到右,即:f1 -> f2 -> f3
这样就能看出其实next 就是 store.dispatch,所以经过层层解析,看到最后返回的就是其实就是被logger包装的dispatch
(action) => {
let returnedValue = store.dispatch(action); // 这里的next就是store.dispatch
return returnedValue;
};
这里我们只用了一个中间件,那么大家可以想想一下,多个中间件是什么样子,其实就是循环调用
dispatch = f1(f2(f3(store.dispatch)));
总结
如果没有中间件的话其实我们就是直接调用store.dispatch(action),但是我们需要对action做一些处理或转换,比如异步操作,异步回调后再执行next;这样的设计还是很巧妙,大家有兴趣可以再细细理解下。