写点什么

【Vuex 源码学习】第七篇 - Vuex 对 State 状态的处理

用户头像
Brave
关注
发布于: 刚刚
【Vuex 源码学习】第七篇 - Vuex 对 State 状态的处理

一,前言


上一篇,主要介绍了 Vuex 模块安装的实现,针对 action、mutation、getter 的收集与处理,主要涉及以下几个点:


  • Vuex 模块安装的逻辑;

  • Vuex 代码优化;

  • Vuex 模块安装的实现;

  • Vuex 初始化流程梳理;


本篇,继续介绍 Vuex 模块相关概念:Vuex 对 State 状态的处理;


二,State 状态的处理


接下来,需要将所有子模块的状态,合并到对应的父模块中;


子模块的 path.length > 0,需要将当前子模块的 State 状态,挂载到它的父模块上;

通过 Vue.set 声明响应式数据


为什么不直接赋值?

因为 Vuex 要求模块是可以动态进行添加的,即 Vuex 能够动态的添加模块

我们希望动态添加的模块也是响应式的数据,因为刚开始的对象没有,后来又有了,需要使用 Vue.set API 为对象新增加一个不存在的属性,等下再注册新模块时,就不同再去变成响应式的了;


Vue.set 也可以直接为对象添加值:如果对象本身不是响应式的,那么 Vue.set 就相当于直接为对象添加了属性, Vue.set 既能解决响应式问题,也能为普通对象进行赋值;


如何找父亲?

if(path.length > 0){ // vuex 可以动态的添加模块  let parent = path.slice(0,-1).reduce((memo,current)=>{    return memo[current]  },rootState)  // 如果这个对象本身不是响应式的 那么Vue.set 就相当于 obj[属性] = 值  Vue.set(parent, path[path.length-1], module.state);}
复制代码

将子模块状态定义到父模块上:

  • 从根模块的状态开始找,返回当前模块所属的父模块 parent;

  • 将当前模块的 State 状态设置到父模块 parent 的 path[path.length-1] 属性中;


即将所有状态都放到 rootState 上


首次,返回 rootState,相当于为根加上 a 和 b 的 state

非首次,找到 a,将 c 定义到 a 的状态中;


打印合并后状态 state(包含全部模块的状态):


根上有 a,b 的状态,a 上有 c 的状态


备注:循环处理当前模块的子模块时,完成 path 的拼接操作;



三,resetStoreVM 方法实现


有了 state 和 getters,需要创建一个实例

创建 resetStoreVM 方法:


传入 this:this 中包含 _wrapperGetters 全部的 getter 方法;

传入 state:rootState 根状态,包含全部的状态;


和之前的实现相同:将 State 状态和 getters 都定义在当前 vm 实例上;

借助一个 Vue 实例,将 state 定义到 data 中,计算属性通过 getters 生成;


在 src/vuex/store.js 中,创建 resetStoreVM 方法:

// src/vuex/store.js
function resetStoreVM(store,state){ const computed = {}; // 定义计算属性 store.getters = {}; // 定义 store 中的 getters // 通过计算属性进行缓存 forEachValue(store._wrappedGetters,(fn, key)=>{ computed[key] = ()=>{ // 将 fn 的执行结果放到计算属性中 return fn(); } // 定义到 store.getters Object.defineProperty(store.getters, key, { get:()=>store._vm[key] // 去计算属性中取值 被代理到 vm 实例上 }); }) // 创建 vm 实例 store._vm = new Vue({ data:{ $$state:state }, computed });}
复制代码


测试:

通过类型,找到对应的数组,数组内存放着所有方法,循环执行即可


四,操作的执行逻辑

commit、dispatch 找到对应的数组并依次执行

export class Store {    constructor(options) {        const state = options.state;        this._mutations = {};        this._actions = {};        this._wrappedGetters = {};        this._subscribes = [];
this._modules = new ModuleCollection(options); installModule(this, state, [], this._modules.root);
// 将 state 和 getters 定义到当前的 vm 实例上 resetStoreVM(this,state); } commit = (type, payload) => { this._mutations[type].forEach(mutation=>mutation.call(this,payload)) } dispatch = (type, payload) => { this._actions[type].forEach(action=>action.call(this,payload)) }}
复制代码


这里使用到了发布订阅模式,先将所有模块中的 mutation 和 action 放到两个数组中,调用时到当前对象中找到对应的数组并依次执行


这样,数据是如何放入,如何执行的就清晰了,后续进行命名空间的处理;


五,结尾


本篇,主要介绍了 Vuex 初始化时对 State 状态的处理,主要涉及以下几个点:


  • State 状态的处理;

  • resetStoreVM 方法实现;

  • 操作的执行逻辑;


下一篇,继续介绍 Vuex 模块相关概念:namespaced 命名空间的实现;


用户头像

Brave

关注

还未添加个人签名 2018.12.13 加入

还未添加个人简介

评论

发布
暂无评论
【Vuex 源码学习】第七篇 - Vuex 对 State 状态的处理