了解了Redux原理之后,我很好奇Redux中间件是怎么运作的,于是选了最常用的redux-thunk进行源码分析。
此次分析用的redux-thunk源码版本是2.2.0,redux源码版本是3.7.2。并且需要了解Redux原理
redux中间件都是由redux的applyMiddleware()方法所挂载的
export default function applyMiddleware(...middlewares) {
return (createStore) => (reducer, preloadedState, enhancer) => {
const store = createStore(reducer, preloadedState, enhancer)
let dispatch = store.dispatch
let chain = []
//暴露给中间件的API,所以redux-thunk可以使用形如return (dispatch, getState)=>{}
const middlewareAPI = {
getState: store.getState,
dispatch: (action) => dispatch(action)
}
//将暴露的API给中间件,调用中间件函数,生成中间件返回值函数(为什么返回值是函数?不是函数下面的compose()就报错了)
chain = middlewares.map(middleware => middleware(middlewareAPI))
//组合全部中间件的返回值函数, chain是中间件返回值函数们
//然后reduce起来的函数返回的也是函数,将store原来的dispatch传进去,dispatch函数也是接受一个action并返回一个action,作为中间件链的头部
dispatch = compose(...chain)(store.dispatch)
return {
...store,
dispatch
}
}
}
可以看到redux主要做了以下事情:
- 对中间件们使用
map
,将dispatch
和getState
传递进去 - 使用
compose
将中间件组合起来,最后传入原生的store.dispatch
而compose
函数则是简单的将中间件进行串联调用
//compose(funcA, funcB, funcC) 等于 (args)=>funcA(funcB(funcC(args)))
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)))
}
最后我们回到redux-thunk
redux-thunk的代码很短,只有短短14行
function createThunkMiddleware(extraArgument) {
return ({ dispatch, getState }) => next => action => {
if (typeof action === 'function') {
return action(dispatch, getState, extraArgument);
}
return next(action);
};
}
const thunk = createThunkMiddleware();
thunk.withExtraArgument = createThunkMiddleware;
export default thunk;
它对外暴露的是const thunk = createThunkMiddleware();
,也就是({dispatch, getState})=>{...}
这个函数。
然后经chain = middlewares.map(middleware => middleware(middlewareAPI))
传入dispatch
和getState
,chain
里面是next=>{...}
,进行compose
。
compose(a,b,c)
的返回值是函数(...args)=>a(b(c(...args)))
,这个函数经调用,传入参数store.dispatch
,之后action
会在中间件链上进行传递,只要保证每个中间件的参数是action
并且将action
传递给下一个中间件。
具体到redux-thunk中,它先检查action
是否是函数,一般的action
都是plain object,如果是函数就应该是由thunk处理。如果不是,传递给next
,next
就是下一个中间件。
如果是函数,则调用这个函数并将dispatch, getState, extraArgument
传入。这也就是为什么我们需要将thunk action生成函数(注意action和action生成函数的区别)写成() => (dispatch, getState) => {...}
,传入redux-thunk的action
就是(dispatch, getState)=>{...}
这个函数
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。