理解redux中间件

198 阅读2分钟

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的时候,利用中间件来执行一系列的副作用。