这两个代码比较少,但是都是精华,放在一起讲。
先说compose文件。
export default 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)))
}
没错,就这么几行代码,这里也用到了将多个函数合并为一个函数的思想,这里接收多个中间件函数并合并为一个函数输出。
首先介绍一下reduce,在一些网站上有他的介绍,在这里他作为一个累加器出现的,确实可以但是在函数式编程的环境下他特殊的处理结构赋予了它新的功能----函数组合。
compose(f, g, h) => 最后返回的是下列结构,正是我们要的函数嵌套函数。
(...args) => f(g(h(...args)))
下面再来看看applyMiddleware,如果这一篇理解的有些困惑,可以联系下一篇一起理解。我总结一句话,
这个函数就是在执行不加第三个参数的CreateStore的基础上,把dispatch这个函数增强一下。
export default function applyMiddleware(...middlewares) {
return (createStore) => (reducer, preloadedState, enhancer) => {
const store = createStore(reducer, preloadedState, enhancer) //这里的函数接收三个参数,不过如果看过createStore源码之后,第三个参数是不需要传递的!
let dispatch = store.dispatch
let chain = [] //定义一个储存中间件函数的列表
const middlewareAPI = {
getState: store.getState,
dispatch: (action) => dispatch(action)
}
chain = middlewares.map(middleware => middleware(middlewareAPI)) //由这部可以看出,middleware需要符合一个规则,即接收getState()和dispatch作为参数。
dispatch = compose(...chain)(store.dispatch) //所以第一个参数是dispatch函数,执行过后返回的也是dispatch。
return {
...store, //返回原有的store结构
dispatch //返回增强过的dispatch
}
}
}
首先看一下函数接收的参数,参数是一系列的middleware,然后将middleware组合起来,返回一个函数。
知根知底,放上一个常用的middleware来举例:
export default function thunkMiddleware({ dispatch, getState }) {
return next => action => { //next是个函数(如果thunkMiddleware在applyMiddware的最右边的话就是store.dispatch),action函数(dispatch)的参数。
if (typeof action === 'function') { //如果diapatch的action是一个函数(中间件),则将dispatch和getState再次传入。
return action(dispatch, getState); //将传入的中间件执行以下,return不写也可
}
return next(action); //这个就是执行的传入的dispatch【即next】,也就是说,这个return,如果每个中间件都写next(action),那返回的始终是原生dispatch的内容,即传入的action.
};
}
上面提到middleware中return不写也可以,只是为了强调,这里重点是将dispatch(传入的参数)执行一下。这里可以做很多事情,比如dispatch一个action的时候,从日志中将action记录一下。
总结:每一个中间件,接收一个dispatch,返回一个dispatch,如上面例子,原生的store.dispatch在该thunkMiddleware中执行一次,然后返回整个dispatch,在下一个dispatch中执行,一直行到最后一个,然后返回dispatch,也就是加强之后的dispatch.