9.1.1 中间件接口
您可以在百度里搜索“深入浅出React和Redux 艾草文学(www.321553.xyz)”查找最新章节!
9.1.1 中间件接口
在Redux框架中,中间件处理的是action对象,而派发action对象的就是Store上的dispatch函数,之前介绍过通过dispatch派发的action对象会进入reducer。其实这不完全正确,因为在action对象进入reducer之前,会经历中间件的管道。
在这个中间件管道中,每个中间件都会接收到action对象,在处理完毕之后,就会把action对象交给下一个中间件来处理,只有所有的中间件都处理完action对象之后,才轮到reducer来处理action对象,然而,如果某个中间件觉得没有必要继续处理这个action对象了,就不会把action对象交给下一个中间件,对这个action对象的处理就此中止,也就轮不到reducer上场了。
每个中间件必须要定义成一个函数,返回一个接受next参数的函数,而这个接受next参数的函数又返回一个接受action参数的函数。next参数本身也是一个函数,中间件调用这个next函数通知Redux自己的处理工作已经结束。
听起来有点绕,通过一个实例会看的更明白。
一个实际上什么事都不做的中间件代码如下:
function doNothingMiddleware({dispatch, getState}) {
return function(next) {
return function(action) {
return next(action);
}
}
}
这个doNothingMiddleware接受一个对象作为参数,对象参数上有两个字段dispatch和getState,分别代表的就是Redux Store上的两个同名函数,不过并不是所有中间件都用得上这两个函数。
函数doNothingMiddleware返回的函数接受一个next类型的参数,这个next是一个函数。如果调用它,代表这个中间件完成了自己的功能,把控制权交给了下一个中间件,但是这个函数还不是处理action对象的函数,它返回的那个以action为参数的函数才是。
以action为参数的函数对传入的action对象进行处理,因为JavaScript支持闭包(Clousure),在这个函数里可以访问上面两层函数的参数,所以可以根据需要做很多事情,包括以下功能:
·调用dispatch派发出一个新action对象;
·调用getState获得当前Redux Store上的状态;
·调用next告诉Redux当前中间件工作完毕,让Redux调用下一个中间件;
·访问action对象action上的所有数据。
具有上面这些功能,一个中间件足够获取Store上的所有信息,也具有足够能力控制数据的流转。
当然,在上面的简单例子中,doNothingMiddleware中间件什么都没有做,只是简单地调用next并把action交给下一个中间件。
读者可能会有一个问题,为什么中间件的接口定义需要这么多层的函数呢?为什么不干脆把接口设计成一个函数接受两个参数store和next,然后返回一个对action处理的函数呢?如果要那样做,上面的doNothingMiddleware就是下面这样定义:
function doNothingMiddleware({dispatch, getState}, next) {
return function(action) {
return next(action);
}
}
如果按照上面这种方法定义中间件接口,似乎更容易理解,但是Redux并没有这么设计,因为Redux是根据函数式编程(Functional Programming)的思想来设计的,函数式编程的一个重要思想就是让每个函数的功能尽量小,然后通过函数的嵌套组合来实现复杂功能,在Redux中我们会看到很多这样的现象。
在前面的章节中,我们使用过redux-thunk中间件来实现异步action对象,现在让我们来揭开redux-thunk的神秘面纱,其实redux-thunk极其简单,代码如下:
function createThunkMiddleware(extraArgument) {
return ({ dispatch, getState }) => next => action => {
if (typeof action === 'function') {
return action(dispatch, getState, extraArgument);
}
return next(action);
};
}
const thunk = createThunkMiddleware();
export default thunk;
在这里,使用了ES6的箭头方式表示函数,连续的=>符号表示的是返回函数的函数,比如下面的代码写法,实际效果和上面的doNothinigMiddleware一样:
({dispatch, getState})=>next=>action=>next(action)
我们看redux-thunk这一串函数中最里层的函数,也就是实际处理每个action对象的函数。首先检查参数action的类型,如果是函数类型的话,就执行这个action函数,把dispatch和getState作为参数传递进去,否则就调用next让下一个中间件继续处理action,这个处理过程和redux-thunk文档中描述的功能一致。
值得一提,每个中间件最里层处理action参数的函数返回值都会影响Store上dispatch函数的返回值。但是,每个中间件中这个函数返回值可能都不一样,像上面的redux-thunk,有可能返回的是下一个中间件返回的结果,也可能返回的是action参数作为函数执行的结果,同时在一个应用中使用的中间件也可能发生变化。所以,dispatch函数调用的返回结果完全是不可控的,我们在代码中最好不要依赖于dispatch函数的返回值。 深入浅出React和Redux