Redux中间件和store enhancer分析
Redux的中间件思想和Koa很相似,Redux的action对象可以类比于Koa中的客户端请求,所有的中间件就组成了处理action对象的管道,最后将处理完成的action对象交给reducer就完成了中间件流程。
applyMiddleware
Redux提供了applyMiddleware方法作为加载中间件的入口,源码如下:
export default function applyMiddleware(...middlewares) {
return (createStore) => (reducer, preloadedState, enhancer) => {
var store = createStore(reducer, preloadedState, enhancer)
var dispatch = store.dispatch
var chain = []
var middlewareAPI = {
getState: store.getState,
dispatch: (action) => dispatch(action)
}
chain = middlewares.map(middleware => middleware(middlewareAPI))
dispatch = compose(...chain)(store.dispatch)
return {
...store,
dispatch
}
}
}
可以看到,该方法的作用是拓展createStore,增强其创建的store的dispatch功能,这也是中间件的作用原理:通过中间件的数组chain改变原始dispatch的内容来达到拓展action对象的目的。
得到数组chain需要对中间件数组传入通用的中间件API并调用中间件函数得到,那么来看一下中间件的通用结构:
const middleware = store => next => action => {
// 传递到下一个中间件前执行的代码
// ...
let result = next(action)
// 传递后执行的代码
// ...
return result
}
可以看到数组chain内存放的都是一个接受参数为next的函数,该参数实际上就是store.dispatch,会在action对象处理完后执行,作用在于将处理过的action对象传递到下一个中间件。传递逻辑实现的关键就是处理数组chain的compose函数。
compose
这个函数就是中间件实现的精华所在了,实际上就是函数式编程中的组合。它将chain中的所有函数组合成一个新的函数并生成一个新的dispatch。源码如下:
function compose(...funcs) {
if (funcs.length === 0) {
return arg => arg
}
if (funcs.length === 1) {
return funcs[0]
}
const last = funcs[funcs.length - 1]
const rest = funcs.slice(0, -1)
return (...args) => rest.reduceRight((composed, f) => f(composed), last(...args))
}
简单理解就是一行代码:
compose(f1, f2, f3)(arg) = f1(f2(f3(arg)));
将数组chain从右到左传原始的store.dispatch执行,每一个中间件数组元素执行后生成包装过的dispatch继续传入下下一个中间件数组元素,reduce完成后即返回最新的result作为最终增强的dispatch。
再回头看一下中间件的通用结构来梳理整套流程。
const middleware = store => next => action => {
// 传递到下一个中间件前执行的代码
// ...
let result = next(action)
// 传递后执行的代码
// ...
return result
}
// 1.接受middlewareAPI作为参数store生成数组chain中的函数,每个函数接受dispatch作为next参数
// 2.从原始dispatch开始从右往左reduce增强,返回的接受action参数的函数即为新的dispatch,最终取代store的dispatch
store enhancer
现在明白了中间件的原理,进一步的就需要理解store enhancer的概念了。前面已经提到了中间件的入口是applyMiddleware函数,实际上这就是一个store enhancer,正如其名,其增强了store的dispatch功能。回头再想想我们是怎么使用applyMiddleware的?
const storeEnhancers = compose(
applyMiddleware(...middlewares),
...
)
const store = createStore(reducer, initialState, storeEnhancers);
createStore接受的第3个参数即为store enhancer,一个store enhancer实际上就是一个高阶函数,参数为创建store的函数,返回值可以创建增强型的创建store的函数用来取代初始createStore,这里的思想和中间件内部增强dispatch的思想一致,同样通过compose合成enhancer数组来获取最终的createStore。
-- EOF --