Vuex
main.js
1 | import Vue from 'vue' |
store/index.js
1 | import Vue from 'vue' |
安装插件
从Vue.use(Vuex)开始,首先Vuex是一个对象

与路由插件一样,都会先执行插件的install方法
1 | function install (_Vue) { |
走进applyMixin方法
1 | function applyMixin (Vue) { |
versions >= 2所以调用Vue.mixin({ beforeCreate: vuexInit });,也就是为所有组件安装beforeCreate声明周期钩子函数
实例化store
进入new Vuex.Store
1 | ... |
1 | var Store = function Store (options) { |
1)初始化模块:Vuex 允许我们将 store 分割成模块(module)。每个模块拥有自己的 state、mutation、action、getter
store 本身可以理解为一个 root module,它下面的 modules 就是子模块,看下创建过程
1 | this._modules = new ModuleCollection(options); |

看一下ModuleCollection构造函数
1 | var ModuleCollection = function ModuleCollection (rawRootModule) { |
这里调用this.register([], rawRootModule, false);,之后通过new Module(rawModule, runtime)创建实例

看一下Module构造函数
1 | var Module = function Module (rawModule, runtime) { |

之后把newModule 赋值给了 this.root

2)安装模块

看下installModule方法
1 | function installModule (store, rootState, path, module, hot) { |
在这里遍历模块中定义的 mutations、actions、getters分别执行它们的注册工作,实现方式差不多,看一下module.forEachGetter
1 | Module.prototype.forEachGetter = function forEachGetter (fn) { |
进入forEachValue(this._rawModule.getters, fn);
1 | function forEachValue (obj, fn) { |
其实就是获取this._rawModule.getters的键名数组,遍历它,最后调用registerGetter(store, namespacedType, getter, local);
1 | function registerGetter (store, type, rawGetter, local) { |
最后添加到store._wrappedGetters上,也就是root store上

3)初始化 store._vm

看一下resetStoreVM
1 | function resetStoreVM (store, state, hot) { |
在这里遍历store._wrappedGetters,之后为store.getters添加属性描述符

也就是访问store.getters上的属性的时候,其实访问的是store._vm上的属性
在下面实例化的store._vm属性

这边调用new Vue,传入computed属性,走初始化计算属性watcher的流程,也传入了data属性
看一下初始化vm的时候传入的store
1 | new Vue({ |
上面是初始化的过程,看下$store是在上面时候挂载到vm实例上的
之前Vuex做install的时候为组件添加的beforeCreate钩子被调用的时候添加的
1 | function vuexInit () { |

前提是创建vm实例的时候,参数传入了store
回到上面的例子
执行到render生成vnode的时候,会调用计算属性的回调获取count

触发state的get

又触发count的get,拿到count的值

也就是在这个阶段完成依赖收集
触发点击事件看一下
1 | increment() { |
1)打印this.$store.state.count,这个没什么好说的
2)第二个获取getters.getCount,在前面resetStoreVM的时候,为属性添加的get描述符被触发

其实就是触发计算属性watcher的get方法(这个计算属性watcher是在上面创建store._vm实例时候创建的),最后调用到getCount方法,右边是调用栈

3)this.$store.dispatch('incrementAction');








在这里触发set

之前做过依赖收集,所以这里做派发更新
触发视图更新就是vm._update(vm._render(), hydrating);
小结
也就是在获取state上的属性的时候会做依赖收集,getter里的属性在创建store._vm实例的时候被当做计算属性,会创建计算属性watcher,在获取的时候会调用回调,dispatch或者commit的时候,最后触发视图更新。