You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
constructor(rawModule,runtime){this.runtime=runtime// 存储子 modulesthis._children=Object.create(null)// Store the origin module object which passed by programmer// 存储原始的这个传进来的 modulethis._rawModule=rawModuleconstrawState=rawModule.state// 获取模块的 state// Store the origin module's statethis.state=(typeofrawState==='function' ? rawState() : rawState)||{}// state 最终是一个对象}
commit(_type,_payload,_options){// check object-style commit// 这里就是获取正确的 type / payload /optionsconst{
type,
payload,
options
}=unifyObjectStyle(_type,_payload,_options)constmutation={
type,
payload
}// 获取触发的type 对应的 mutationconstentry=this._mutations[type]if(!entry){// 如果不存在,给出警告if(process.env.NODE_ENV!=='production'){console.error(`[vuex] unknown mutation type: ${type}`)}return}this._withCommit(()=>{// 由于entry是一个数组,所以逐个执行,并传入负载entry.forEach(functioncommitIterator(handler){handler(payload)})})// 触发 订阅函数this._subscribers.forEach(sub=>sub(mutation,this.state))if(process.env.NODE_ENV!=='production'&&options&&options.silent){console.warn(`[vuex] mutation type: ${type}. Silent option has been removed. `+'Use the filter functionality in the vue-devtools')}}dispatch(_type,_payload){// 基本和commit 一样// xxx}
看完上面的代码,我有些疑问,这个 store.state 和 store.getter 是哪来的?
resetStoreVM(this, state)
functionresetStoreVM(store,state,hot){constoldVm=store._vm// 之前的 vue 实例// bind store public gettersstore.getters={}// 终于找到你 constwrappedGetters=store._wrappedGetters// 前面说过的各个模块的 getters 集合constcomputed={}forEachValue(wrappedGetters,(fn,key)=>{// use computed to leverage its lazy-caching mechanismcomputed[key]=()=>fn(store)// 收集各个 getter,等会传入 computed ,以此做到响应式Object.defineProperty(store.getters,key,{get: ()=>store._vm[key],// 因为利用了计算属性,所以各个 getter 就变成了 vue 实例的属性enumerable: true// for local getters})})// use a Vue instance to store the state tree// suppress warnings just in case the user has added// some funky global mixinsconstsilent=Vue.config.silent//// 是否取消Vue 所有的日志与警告Vue.config.silent=true// 重新 new store._vm=newVue({data: {$$state: state// 这里虽然是 $$state,但是利用store.state时获取的就是它},
computed
})/* get state() { return this._vm._data.$$state }*/Vue.config.silent=silent// enable strict mode for new vmif(store.strict){enableStrictMode(store)}if(oldVm){if(hot){// 解除旧vm的state的引用,以及销毁旧的Vue对象// dispatch changes in all subscribed watchers// to force getter re-evaluation for hot reloading.store._withCommit(()=>{oldVm._data.$$state=null})}Vue.nextTick(()=>oldVm.$destroy())}}
if(!isRoot&&!hot){// 如果不是根模块以及 hot = false,这里我们是根模块,所以我们先放一放,跳到下一步constparentState=getNestedState(rootState,path.slice(0,-1))constmoduleName=path[path.length-1]store._withCommit(()=>{Vue.set(parentState,moduleName,module.state)})}
书接上回,上回书说了 vuex 的安装、以及
store
构造函数,下面我们来讲后面部分收集 modules
vuex 允许我们自定义多个模块,防止应用的所有状态会集中到一个比较大的对象,导致 store 就变的臃肿了。
这是如何实现的呢?
在store的构造函数里面有这样一段代码:
this._modules = new ModuleCollection(options)
,他就是用来收集用户自定义的modules
,该函数位于module/module-collection.js
下现在假设我们的 modules 做如下设置:
模块关系图如下:
来到
ModuleCollection
的构造函数,很简单,调用其register
方法,并传入三个参数现在我们一步一步来分析。
先讲一下
register
里的对传入模块结构的断言,调用assertRawModule(path, rawModule)
以确保getters/mutations/actions
依次符合函数/函数/(对象或者函数)
的结构,这部分代码并不难,但是作者的这种编码习惯非常值得学习,详见 assertRawModule回到正题
第一次 调用
this.register([], rawRootModule, false)
此时传入
register
函数的path
为空数组
,rawModule 为最外层的store
对象,即可以理解为根module
,runtime 为false
接着调用
new Module(rawModule, runtime)
实例化这个根module
回到
register
函数,如果此时的 path 为 空数组,那么就将此模块设置为 整个状态树的根模块
,即this.root= 根 module
,这里我们的path=[]
,所以它是根 module
,不走else
来到后面,判断该模块是否有
modules
属性,即有子模块,有则继续循环注册子模块,我们这里有moduleA
和moduleB
,所以继续注册第二次调用
this.register(path.concat(key), rawChildModule, runtime)
此时传入
register
函数的path
为path.concat(key)
,即path =['moduleA']
,rawModule 为moduleA
对象,runtime 为false
继续重复第一步的步骤,不同的是,实例化完
moduleA
后,由于此时的path =['moduleA']
,所以它走else
path.slice(0, -1)
返回 path 数组以外的其他元素,不改变原始数组,所以等价于this.get([])
this.root
为前面的根 module
,而 path 是空,所以parent=根 module
,然后执行parent.addChild(path[path.length - 1], newModule)
,此时获取 path 栈顶元素("moduleA"
)作为 key ,和 实例moduleA
作为 value ,加入到 父模块(根 module)的子元素对象中由于
moduleA
还有子模块,所以继续递归 子模块第三次调用
this.register(path.concat(key), rawChildModule, runtime)
此时传入
register
函数的path
为path.concat(key)
,即path =['moduleA']
,rawModule 为moduleA
对象,runtime 为false
继续上面步骤
来到
this.get
,这是传入的参数是['moduleA']
,即moduleC
的父模块moduleA
。由于根module
保存了moduleA
,所以通过这种类似于链的方式来获取父模块
,同理将moduleC
加入moduleA
的子模块对象中至此,第一条链就讲完了,
返回到
根module
的forEachValue
循环中,这里我们讲到,他的path 还是空
,这就体现了 使用concat
方法的好处与机智。 所以与处理moduleA
的过程一模一样第四次调用
this.register(path.concat(key), rawChildModule, runtime)
此时传入
register
函数的path
为path.concat(key)
,即path =['moduleB']
,rawModule 为moduleB
对象,runtime 为false
终于将
this._modules = new ModuleCollection(options)
的过程分析完毕了最终的
this._modules.root(不包括方法)
如下图所示总的看下来挺佩服作者的思维以及处理方式的
看着挺长的了,其实就是多了几个循环过程的讲解,所以要不要再翻篇呢?呢?呢?????
回到
store.js 的构造函数
,installModule(this, state, [], this._modules.root)
初始化根模块,并且递归注册子模块,并且收集所有模块的 getters
上面出现的有关函数由于排版以及篇幅原因,我放到了 我看Vue(三) 中。
总结下,installModule 都干了些神马:
dispatch/commit/getter/state
等属性或方法mutations/getters/actions
加入到全局的_mutations /_wrappedGetters/_actions
里接下来我们简单讲讲 在组件里面调用
dispatch、commit
的过程dispatch/commit
看完上面的代码,我有些疑问,这个
store.state
和store.getter
是哪来的?resetStoreVM(this, state)
解决了 store.getter了,那么 store.state是如何来的呢?
还记不记得第一次让你跳的地方,没错就是
installModule
这里我们就来看
Vue.set(parentState, moduleName, module.state)
。 它的作用是在父模块的state 属性上添加上本模块的state,还是按照一开始我们那种依赖关系来看:这样我们就不难理解
getNestState
里面为什么可以如此获取state
了好了,
vuex
核心大致的内容就是这些,后面在 我看Vuex(三)中我会解释下其他一些函数的作用
如有不当,欢迎指出交流,谢谢
^_^
The text was updated successfully, but these errors were encountered: