redux的applyMiddleware的第二部分细节

原文: redux的applyMiddleware细节分析

在上篇文章中有提到中间件里有定义一个dispatch方法用来抛出异常,然后在middlewareAPI里调用的时候是携带参数了:

const middlewareAPI = {
   getState: store.getState, //获取store里的state
   dispatch: (...args) => dispatch(...args) // 调用`dispatch`的时候会抛错,如果在组合中间件之前调用,下面会说
}

一开始我以为是在调用的时候就会报错,可是发现这个对象里的dispatch携带参数,如果只是单纯抛错,完全可以不需要传递参数,然后向下看下去才看到其中的奥妙。

到底奥妙在哪里,这段抛错代码究竟是有什么作用。

先说这段代码的作用: 防止在对dispatch扩展之前调用dispatch

我们来写个简单的middleware:

const exampleMiddle = ({getState, dispatch}) => next => action => {
    console.log('exampleMiddleware action is', action)
    return next(action) 
}

假设我们当前并不知道那段dispatch函数抛出错误的作用,我们可以根据applyMiddleware代码来推算出来。

我们知道,在代码里有对dispatch重新赋值操作:

dispatch = compose(...chain)(store.dispatch)

所以我们可以知道,在这个赋值之前调用的dispatch都是会抛错的(就是那段单纯抛出错误的dispatch函数)。

所以为了证明这个,我们来试下:

const exampleMiddle = ({getState, dispatch}) => next => {
  console.log('dispatch action', dispatch({}))
  return action => {
    console.log('exampleMiddleware action is', action)
    return next(action)
  }
}

然后你就会发现console里有错误抛出,就是那段dispatchthrow

然后我们在dispatch = compose(...chain)(store.dispatch)之后再次调用dispatch
也就是在最终触发action的时候再调用,发现是可以调用(需要加判断是否调用过,否则就会死循环。后面解释为啥死循环。)

会不会感觉不太对,为啥在闭包作用域链外的更改会影响到闭包内的变量?

先来证明,闭包内的变量不受外部改变:

let name = 'first arg'
function run(firstArg){
  console.log('run params is', firstArg)
  return function next(){
    console.log('next params is', firstArg)
  } 
}
let next = run(name)
name = 'changed'
next() // next params is first arg

对吧,说明外部的更改是不会影响到内部的变量的。因为作用域链已经生成了。

我们再来看看另外一个情况:

let age = 99
let obj = {
  old: age,
  young: () => age
}
age = 18
obj.old // 99
obj.young() // 18

很明了了吧,因为每次函数调用的都是当前作用域链的变量。如果对于这部分不理解,可以看这篇文章进行深入了解。

可以发现我们自己写的exampleMiddleware里,第一个参数里有传入dispatch,然后返回的参数里携带了一个next参数(store.dispatch), 为什么还要传递dispatch, 并且dispatch也不可以在前面使用,只能在到action这步的时候才可以。所以为啥还要传递dispatch进来,直接传递了store.dispatch不是更好吗? 这两个不等价,store.dispatch是原生的dispatch,所以可以直接返回,不会出现死循环。参数dispatch是组合中间件之后的dispatch,所以简单的直接调用会死循环,会自己调用自己,所以需要判断下。

总结: middlewares通过compose组合这些中间件成一个链式的dispatch,这样每次dispatch都会运行处理,可以发现dispatch源码里,最后返回的是action

你可能感兴趣的:(redux的applyMiddleware的第二部分细节)