vuex和单纯全局对象的不同
- Vuex 的状态存储是响应式的
- 限制直接修改, 保留每次修改的记录. 改变 store 中的状态的唯一途径就是显式地提交 (commit) mutation。
|
|
plugin初始化
- vuex用法就是install时注册$store, 然后再
new Vuex.Store
传给vue option, 子组件便可以获取到根组件的state - 从$options里获取store, 没有就从parent获取, 设置到$store12345678910111213141516function install(_Vue) {if (Vue && _Vue === Vue) returnVue = _VueVue.mixin({ beforeCreate: vuexInit })}function vuexInit () {const options = this.$options// store injectionif (options.store) {this.$store = typeof options.store === 'function'? options.store(): options.store} else if (options.parent && options.parent.$store) {this.$store = options.parent.$store}}
Store 实例化
- Store的实例化过程拆成 3 个部分,分别是初始化模块,安装模块和初始化 store._vm123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051new Vuex.Store({actions,getters,state,mutations,modules// ...})function Store (options = {}) {var this$1 = this;if (!Vue && typeof window !== 'undefined' && window.Vue) {install(window.Vue);}var plugins = options.plugins; if ( plugins === void 0 ) plugins = [];var strict = options.strict; if ( strict === void 0 ) strict = false;// store internal statethis._committing = false;this._actions = Object.create(null);this._actionSubscribers = [];this._mutations = Object.create(null);this._wrappedGetters = Object.create(null);this._modules = new ModuleCollection(options); // 初始化模块this._modulesNamespaceMap = Object.create(null);this._subscribers = [];this._watcherVM = new Vue();// bind commit and dispatch to self// strict modethis.strict = strict;var state = this._modules.root.state;// init root module.// this also recursively registers all sub-modules// and collects all module getters inside this._wrappedGettersinstallModule(this, state, [], this._modules.root); // 安装模块// initialize the store vm, which is responsible for the reactivity// (also registers _wrappedGetters as computed properties)resetStoreVM(this, state); // 初始化 store._vm// apply pluginsplugins.forEach(function (plugin) { return plugin(this$1); });if (useDevtools) {devtoolPlugin(this);}};
ModuleCollection 初始化模块 生成_modules的树形结构数据
- 注册根模板
this.register([]:, rawRootModule: 模块组成, false: 是否运行时创建);
- 根module没有路径[], 路径格式[‘parent’,’child’]常用reduce去逐层深入获取module对象
- 创建module
var newModule = new Module(rawModule, runtime);
- 设置父子关系
- 包含子模块递归注册12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455// ModuleCollectionvar ModuleCollection = function ModuleCollection (rawRootModule) {// register root module (Vuex.Store options)this.register([], rawRootModule, false);};ModuleCollection.prototype.get = function get (path) {return path.reduce(function (module, key) {return module.getChild(key)}, this.root)};ModuleCollection.prototype.getNamespace = function getNamespace (path) {var module = this.root;return path.reduce(function (namespace, key) {module = module.getChild(key);return namespace + (module.namespaced ? key + '/' : '')}, '')};ModuleCollection.prototype.update = function update$1 (rawRootModule) {update([], this.root, rawRootModule);};ModuleCollection.prototype.register = function register (path, rawModule, runtime) {var this$1 = this;if ( runtime === void 0 ) runtime = true;if (process.env.NODE_ENV !== 'production') {assertRawModule(path, rawModule);}var newModule = new Module(rawModule, runtime);if (path.length === 0) {this.root = newModule;} else {var parent = this.get(path.slice(0, -1));parent.addChild(path[path.length - 1], newModule);}// register nested modulesif (rawModule.modules) {forEachValue(rawModule.modules, function (rawChildModule, key) {this$1.register(path.concat(key), rawChildModule, runtime);});}};ModuleCollection.prototype.unregister = function unregister (path) {var parent = this.get(path.slice(0, -1));var key = path[path.length - 1];if (!parent.getChild(key).runtime) { return }parent.removeChild(key);};
|
|
|
|
安装模块
- 注册名称空间到store
_modulesNamespaceMap
(变量名前加路径dispatch('account/login')
) - 设置响应式
- makeLocalContext创建上下文
- 3 个参数相关,store 表示 root store;namespace 表示模块的命名空间,path 表示模块的 path。
- 子模块的里的Dispatch,commit遇到名称空间会自动拼上
- state获取对应名称空间的state, getter返回同名称空间下的getter
- 注册action,mutation,getter,递归安装子模块(拼上名称空间放到store._mutations, store._actions,store._wrappedGetters)
- 要看传参就去看对应的registerxxxx函数在call时传入什么123456function registerMutation (store, type, handler, local) {var entry = store._mutations[type] || (store._mutations[type] = []);entry.push(function wrappedMutationHandler (payload) {handler.call(store, local.state, payload); //});}
- 要看传参就去看对应的registerxxxx函数在call时传入什么
|
|
|
|
初始化 store._vm
- resetStoreVM 的作用实际上是想建立 getters 和 state 的联系,因为从设计上 getters 的获取就依赖了 state ,并且希望它的依赖能被缓存起来,且只有当它的依赖值发生了改变才会被重新计算。因此这里利用了 Vue 中用 computed 计算属性来实现。
- store.getters从computed获取,computed执行
rawGetter(local.state,...) 方法
那么就会访问到 store.state,进而访问到 store._vm._data.$$state,这样就建立了一个依赖关系。当 store.state 发生变化的时候,下一次再访问 store.getters 的时候会重新计算。 Object.defineProperties( Store.prototype, prototypeAccessors$1 );
store.state从store._vm._data.$$state
来enableStrictMode
store._vm会deep watchthis._data.$$state
直接修改state会警告, store.state 被修改的时候, store._committing 必须为 true
|
|
API和语法糖
- state,getter map到computed里. mutation,action map到 methods里
mapState
- normalizeNamespace自动加末尾斜杠, normalizeMap转key-value数组格式
- getModuleByNamespace按名称空间获取module
- 最终收集了computed的watcher到state.dep里1234mapState('some/nested/module', {a: state => state.a,b: state => state.b})
|
|
模块动态更新
- 刷新vm1234567891011121314151617181920212223registerModule (path, rawModule, options = {}) {if (typeof path === 'string') path = [path]this._modules.register(path, rawModule)installModule(this, this.state, path, this._modules.get(path), options.preserveState)// reset store to update getters...resetStoreVM(this, this.state)}unregisterModule (path) {if (typeof path === 'string') path = [path]if (process.env.NODE_ENV !== 'production') {assert(Array.isArray(path), `module path must be a string or an Array.`)}this._modules.unregister(path)this._withCommit(() => {const parentState = getNestedState(this.state, path.slice(0, -1))Vue.delete(parentState, path[path.length - 1])})resetStore(this)}
|
|
插件
subscribe 的逻辑很简单,就是往 this._subscribers 去添加一个函数,并返回一个 unsubscribe 的方法。
而我们在执行 store.commit 的方法的时候,会遍历 this._subscribers 执行它们对应的回调函数:
|
|