共计 2345 个字符,预计需要花费 6 分钟才能阅读完成。
上集回顾
Redux 是如何使用的?首先再来回顾一下这个使用 demo(谁让这段代码完整地展示了 redux 的使用)
如果有小伙伴对这段代码不是很理解的话,建议先去学习 Redux 的使用再来看这篇源码,这样更加事半功倍。通过上段代码,我们拆分几个比较核心的点,我一一列举一下:
action 的结构是如何的?
如何去定义一个 reducer?
combineReducers 是如何整合多个 reducer 的?
createStore 是如何创建一个 store?
5.dispatch 拿到 action 到底干了什么?
subscribe 是如何监听状态发生改变的?
getState 是如何拿到所有的状态值的?
上期我们先解决了前三个疑问,这期我们一起来探索后 4 个问题。
4、createStore 是如何创建一个 store?
首先我们先撸一个 createStore 架构出来:
通过这段代码我们知道了传参应该是什么样子和返回了什么。从中我发现了一个问题,createStore 接受的是三个参数:1、reducer 2、预加载的 state 3、redux-thunk 之类的增强器。但是我们平时经常会写成如下这个样子:
我们会在第二个参数就传入了增强器,这跟源代码的参数结构不符哎,但是为什么就可以这么用了。接下来我们就看一下,reducer 是如何做这个处理的。
当第二个参数 preloadedState 的类型是 Function 的时候,并且第三个参数 enhancer 未定义的时候,此时 preloadedState 将会被赋值给 enhancer,preloadedState 会替代 enhancer 变成 undefined 的。有了这么一层转换之后,我们就可以大胆地第二个参数传 enhancer 了。
解决了这个疑问之后,往下就是解释一下他返回的值是什么东西,这些解答我们就放在下面做解释,这里就不做赘述了。不过在接下去之前,我们得搞清楚下面这组变量代表啥意思。
其中变量 isDispatching,作为锁来用,我们 redux 是一个统一管理状态容器,它要保证数据的一致性,所以同一个时间里,只能做一次数据修改,如果两个 action 同时触发 reducer 对同一数据的修改,那么将会带来巨大的灾难。所以变量 isDispatching 就是为了防止这一点而存在的。
5、dispatch 拿到 action 到底干了啥?
函数 dispatch 在函数体一开始就进行了三次条件判断,分别是以下三个:
1. 判断 action 是否为简单对象
2. 判断 action.type 是否存在
判断当前是否有执行其他的 reducer 操作
当前三个预置条件判断都成立时,才会执行后续操作,否则抛出异常。在执行 reducer 的操作的时候用到了 try-finally,可能大家平时 try-catch 用的比较多,这个用到的还是比较少。执行前 isDispatching 设置为 true,阻止后续的 action 进来触发 reducer 操作,得到的 state 值赋值给 currentState,完成之后再 finally 里将 isDispatching 再改为 false,允许后续的 action 进来触发 reducer 操作。接着一一通知订阅者做数据更新,不传入任何参数。最后返回当前的 action。
6、subscribe 是如何监听状态发生改变的?
在注册订阅者之前,做了两个条件判断:
判断监听者是否为函数
是否有 reducer 正在进行数据修改(保证数据的一致性)
接下来执行了函数 ensureCanMutateNextListeners,下面我们看一下 ensureCanMutateNextListeners 函数的具体实现逻辑:
逻辑很简单,判断 nextListeners 和 currentListeners 是否为同一个引用,还记得初始变量定义那以及函数 dispatch 内部那两处的代码吗?
这两处将 nextListeners 和 currentListeners 引用了同一个数组,而 ensureCanMutateNextListeners 就是用来判断这种情况的,当 nextListeners 和 currentListeners 为同一个引用时,则做一层浅拷贝,这里用的就是 Array.prototype.slice 方法, 该方法会返回一个新的数组,这样就可以达到浅拷贝的效果。
函数 ensureCanMutateNextListeners 作为处理之后,将新的订阅者加入 nextListeners 中,并且返回取消订阅的函数 unsubscribe。函数 unsubscribe 执行时,也会执行两个条件判断:
是否已经取消订阅(已取消的不必执行)
是否有 reducer 正在进行数据修改(保证数据的一致性)
通过条件判断之后,将该订阅者从 nextListeners 中删除。看到这里可能有小伙伴们对 currentListeners 和 nextListeners 有这么一个疑问?函数 dispatch 里面将二者引用同一个数组,为啥这里将二者分别引用两个值相同的数组?直接用 currentListeners 不可以吗?这里这样做其实也是为了数据的一致性,因为有这么一种的情况存在。当 redux 在通知所有订阅者的时候,此时又有一个新的订阅者加进来了。如果只用 currentListeners 的话,当新的订阅者插进来的时候,就会打乱原有的顺序,从而引发一些严重的问题。
7、getState 是如何拿到所有的状态值的?
getState 相比较 dispatch 要简单许多, 返回 currentState 即可,而这个 currentState 在每次 dispatch 得时候都会得到响应的更新。同样是为了保证数据的一致性,当在 reducer 操作的时候,是不可以读取当前的 state 值的。
看完是不是已满腔热血
充满了斗志?