redux使用中间件,是通过applyMiddleware函数来实现:
const store = createStore(
reducer,
applyMiddleware(middlewares)
)
看一下createStore中如何处理applyMiddleware:
if (typeof enhancer !== 'undefined') {
if (typeof enhancer !== 'function') {
throw new Error('Expected the enhancer to be a function.')
}
return enhancer(createStore)(reducer, preloadedState)
}
可以看到, enhancer(createStore)得到的是一个增强版的createStore, 具体到applyMiddleware,它的函数签名就应该是这样的:
(...middlewares) => createStore => (...args) => store
最终返回的store,它的dispach已经被修改了,dispatch的时候,会执行一系列的中间件函数。
按照redux的设计,所有的中间件接收getState和dispatch两个参数,返回一个函数:
next => action => {
//在这里调用next(action)会把action传递给下一个中间件
}
举个例子,这里考虑中间件只有两个的情况:
function middleware1({getState, dispath}){
const fn1 = next => action => {
console.log('middleware1 start')
const result = next(action)
console.log('middleware1 end')
return result
}
return fn1
}
function middleware2({getState, dispath}){
const fn2 = next => action => {
console.log('middleware2 start')
const result = next(action)
console.log('middleware2 end')
return result
}
return fn2
}
applyMiddleware会把所有中间件函数先执行一遍,把返回的函数存放在数组chain中。 applyMiddleware内部是怎么把存放在数组chain里面的中间件串联起来呢? 它使用compose函数:
dispatch = compose(...chain)(store.dispatch)
最终的dispatch是这样的
function(action){
doSomething()//action传递到第二个中间件前
const res = next(action) // 交出控制权,action传递到下一个中间件
doSomething()//控制权回到第一个中间件
return res
}
compose函数干了这么一件事:
(fnA, fnB, fnC) => (...args) => fnA(funB(funC(...args)))
我们的中间件只有两个,所以compose函数使得中间件以这样的方式调用:
fn1(fn2(store.dispatch))
对于fn1来说,参数next就是fn2返回的
function(action){
console.log('middleware2 start')
const result = next(action)
console.log('middleware2 end')
return result
}
,fn1通过调用next,把action传递到fn2,fn2又可以通过调用next把action再传递到下一个中间件。最后一个中间件的参数next是真正的store.dipach,action是原始的action。
到这里我们就可以明白applyDiddlware是怎样改写dispatch,使得分发action的时候,利用中间件来执行一系列的副作用。