Redux的applyMiddleware源码分析

redux中dispatch只能是object对象,这对于同步的操作是可行的,但如果是异步的操作,那么将行不通,对此,redux提供了applyMiddleware来增强相应的disptch方法,同时将applyMiddleware返回的函数作为参数传入createStore中,替换当前store中的dispatch方法。
下面我们具体结合redux-thunk中间件来分析下dispatch增强的源码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
// applyMiddleware源码

export default function applyMiddleware(...middlewares) {
return createStore => (...args) => { //传入createStore保证middleware只会在store上应用一次
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和dispatch传入middleware中
getState: store.getState,
dispatch: (...args) => dispatch(...args)
//这时dispatch是上述构造的方法,当dispatch被中间件改造后则dispatch为改造后的
}
const chain = middlewares.map(middleware => middleware(middlewareAPI))
dispatch = compose(...chain)(store.dispatch)
// 将原先的store.dispatch作为参数next传入middleware中
// compose将多个function如a,b,c。compose(a,b,c)将返回(...args) => a(b(c(...args))),
// 即dispatch action时, c函数作为b函数的next,b函数作为a函数的next,所以将依次执行函数a,b,c。
// dispatch被中间件改造了

return {
...store,
dispatch
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
// redux-thunk源码

function createThunkMiddleware(extraArgument) {
return ({ dispatch, getState }) => next => action => {
//next是store上的dispatch方法
if (typeof action === 'function') {
//如果action返回的是function则继续将dispatch方法往下传,直到action非function类型
return action(dispatch, getState, extraArgument);
}
//如果action为非function类型,则调用store.dispatch方法
return next(action);
};
}
1
2
3
4
5
6
7
8
9
10
11
12
// createStore中的片段代码

export default function createStore(reducer, preloadedState, enhancer) {
...
if (typeof enhancer !== 'undefined') {
if (typeof enhancer !== 'function') {
throw new Error('Expected the enhancer to be a function.')
}
//将createStore和reducer,初始state传入applyMiddleware中创建store
return enhancer(createStore)(reducer, preloadedState)
}
...

通过applyMiddleware传入中间件增强了dispatch方法,并返回增强的dispatch和其他的createStore上的方法。


本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!