注册
install -> applyMixin->vuexInit
这里只分析Vue2的注册,因为Vue1我也没用过。
其实就是调用了Vue的静态方法mixin。静态方法mixin是全局混入,会在每一个实例的options内添加beforeCreate回调函数。
vuexInit内的options指的是每一个vue实例的options。
在最外面的App根组件上引入了store属性,因此app组件上就有了$store属性,
随后以this.store=options.parent.store = options.parent.store=options.parent.store的方式将所有vm实例的$store在组件初始化时全部指向了app根组件的store值。
即,this.$store 其实是 Store的实例。Vuex可以创建多个Store实例,但是一般而言一个Store已经够用了。
Vuex其实是一种状态管理方式,脱离了Vue也可以使用。
初始化模块(一):new Module与建立Module的父子关系
ModuleCollection构造函数:register
构造函数调用了register方法
这里根本上是根据options来创建module并且建立父子关系。具体阐述如下注释:
Module类其实内部保存的数据不多,只是一个rowModule与state而已。
初始化模块(二):installModule
installModule
获取模块的命名空间,然后递归安装所有的模块,其中有几个重要的方法要分析一下。
makeLocalContext:创建模块的本地执行上下文环境
这里传入的store为当前的store实例,命名空间为当前安装模块的命名空间,path为路径数组,root Module为[]
makeLocalContext
makeLocalGetters
使用gettersProxy代理对象,当获取模块内部的getters时,其实访问的是gettersProxy对象,gettersProxy对象做的事情就是方便在模块内部访问某一个getter时,可以不添加命名空间就可以取值。
至此,const local = (module.context = makeLocalContext(store, namespace, path))的过程已经全部清楚了
registerMutation
registerAction
registerGetters
初始化模块(三):resetStoreVM(this, state)
将getters,state加入响应式系统,只有这两个属性是因为vuex中只有这两个属性有关,action与dispatch都是改变数据的动作。
resetStoreVM,其实就做了两件事:
1. 给store添加getters属性,将所有的getter都添加到该属性内;
2. new Vue,构造函数内传入computed与data,computed值为包裹后的getters,data为state。这样getters与state的数据就加入了响应式系统。
小结
在Vuex中,数据是存储在module内部的state对象与getters对象之中。
简单来讲,可以看到store上定义了很多的内部属性,最难的部分其实是getters,因为很绕。
但是从数据获取途径的角度来看就会迎刃而解。
数据从store实例获取
初始化Vuex执行installModule的时候,registerGetter函数将原始的getter函数座一层包裹(warappedGetter),存储在store._wrappedGetters中。
执行resetStoreVM的时候,store.getters添加了store._wrappedGetters中所有的getters。
store._wrappedGetters是个中转站,工具人
通过store.getters[key]直接获取getter,值为wrappedGetter,传入了local.getters,local.state,store.getters,store.state。
所以rawGetter可以获取到上述参数。
数据从内部获取的角度
module内部的mutations对象与actions对象内的方法可以获当前module的getters/state与全局的state。
当在以module内部的视角看数据的时候,是不会在意namespace这个值的,因为在module内部就只有一个namespace。因此使用了gettersProxy对象来将当前module的getter与store实例上的getters联系起来,即gettersProxy的key不带命名空间,值为store.getters内带有命名空间的getter函数(wrappedGetter)。
local对象
local对象内有getters,为了提升性能,做了一层Cache,将getters保存到_makeLocalGettersCache对象,key为命名空间,value为gettersProxy。
local.getters
local.getters拿到了gettersProxy的值。那么将local传入wrapperedGetter函数就可以获取local的值了,同样地,传入store就可以拿到全局的值。传入其他处理后的action,dispatch就可以拿到特定的local和全局的getters/state。
所以,看起来是在内部访问的数据,其实最终还是访问了store.getters。而使用gettersProxy对象也是为了做一层缓存,并且可以在module内部取getter值的时候可以不写命名空间。
其他
在commit与dispatch的方法中含有type参数,在module内部书写type的时候,makelocalContext函数已经为type添加了namespace,因此可以直接写不带namespace的type参数。