redux添加中间件需要使用到一个redux原生提供的一个方法 applyMiddleware
, 我们就从这个方法说起
整个中间件部分代码不多, 但是函数的嵌套层级较多, 很容易乱
applyMiddleware
先看源码:
export default function applyMiddleware(...middlewares) {
return createStore => (...args) => {
const store = createStore(...args)
let dispatch = () => {
throw new Error(
'Dispatching while constructing your middleware is not allowed. ' +
'Other middleware would not be applied to this dispatch.'
)
}
const middlewareAPI = {
getState: store.getState,
dispatch: (...args) => dispatch(...args)
}
const chain = middlewares.map(middleware => middleware(middlewareAPI))
dispatch = compose(...chain)(store.dispatch)
return {
...store,
dispatch
}
}
}
这个函数我们在使用的时候大致是这样的
const store = createStore(reducer, preloadedState, applyMiddleware( thunk, logger ))
所以我们传入createStore的实际是他的返回值 (createStore)=> (...args)=> store
—— 一个接收 createStore
函数, 返回另一个接收任意数量参数返回store
对象的函数, 我们叫他enhancer
这点你可能会迷, createStore 为什么会出现在这, createStore 自己又干了什么?
至于createStore内部干了什么我们先不多说, 我们先记住:
一旦createStore内部检测到我们传入了
enhancer
, 就会调用并返回enhancer
的执行结果
if (typeof enhancer !== 'undefined') {
if (typeof enhancer !== 'function') {
throw new Error('Expected the enhancer to be a function.')
}
return enhancer(createStore)(reducer, preloadedState) // 把控制权交给了applyMiddleware
}
简单来讲enhancer
内部就是创建了store
, 但是并没有立即把store
返回给你用, 而是依照顺序
调用你传入的中间件去修改dispatch
, 再把修改后的dispatch
放进store
中返回给你
这里值得注意的就是这个中间件调用顺序
const chain = middlewares.map(middleware => middleware(middlewareAPI))
dispatch = compose(...chain)(store.dispatch)
第一行: 正序调用
你传入的所有中间件函数, 并保存执行结果数组
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)))
}
第二行: 调用这个compose
函数对执行结果数组
转换格式
funcs.reduce((a, b) => (...args) => a(b(...args)))
第一次看见这种写法应该会迷, 实际就是这样
const funcs = [fun1, fun2, fun3, fun4]
funcs.reduce((a, b) => (...args) => a(b(...args)))
// (...args)=> fun1(fun2(fun3(fun4(...args))))
下一节我们找个中间件的源码套上去试试, 再理解一下中间件的写法