redux的中间件(middleware)

时间:2022-08-31 20:01:09

applyMiddleware的实现

首先我们来看下applyMiddleware源码实现,代码如下所示:

export default function applyMiddleware(...middlewares) {
return (createStore) => (reducer, preloadedState, enhancer) => {
var store = createStore(reducer, preloadedState, enhancer)
var dispatch = store.dispatch
var chain = []

var middlewareAPI = {
getState: store.getState,
dispatch: (action) => dispatch(action)
}
chain = middlewares.map(middleware => middleware(middlewareAPI))
dispatch = compose(...chain)(store.dispatch)

return {
...store,
dispatch
}
}
}

其中:
1、applyware执行完成后会返回一个闭包,该闭包接受的参数为createStore。这个闭包会在createStore方法中被执行。这样就可以在所有的middleware*享store了。
2、compose方法会基于middlewares和store.dispatch生成一个新的dispatch。
3、最终用新生成的dispatch来替换store中原有的dispatch。
由上可知,其中最关键的也就是compose方法:

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)))
}

其中args参数为store.dispatch,而且每个middleware在定义时也可以接收dispatch参数,具体见中间件的结构。

参照文档可知,[0, 1, 2, 3, 4].reduce( (prev, curr) => prev + curr ) 的执行如下:
redux的中间件(middleware)
最后一次函数调用的返回值 (10) 作为reduce函数的结果被返回。

中间件的结构

中间件的结构如下:

function ({getState, dispatch}) {
return function (next) {
return function (action) {...}
}
}

applyMiddleware中的middlewares.map执行后,中间件返回为:

function (next) {
return function (action) {...}
}

当compose执行完毕后,就会生成新的dispatch。在每个中间件中可以基于自己的判断,action是否交个下一个middleware去处理,还是自己处理完毕后直接调用dispatch。

中间件的执行过程

假设我们有3个中间件A、B、C,

A = ({dispatch}) => next => action => {
if(conditionA){
return dispatch(action)
}
return next(action);
}
B = ({dispatch}) => next => action => {
if(conditionB){
return dispatch(action)
}
return next(action);
}
C = ({dispatch}) => next => action => {
if(conditionC){
return dispatch(action)
}
return next(action);
}

则最终生成的dipatch类似与:

newDispatch = action => {
if(conditionA){
return dispatch(action)
}
return (action) => {
if(conditionB){
return dispatch(action)
}
return (action) => {
if(conditionC){
return dispatch(action)
}
return next(action); //这时,C中的next为store.dispatch
}
}

这样,在中间件中就可以判断如何对action进行处理。