Bootstrap

【Vuex 源码学习】第三篇 - Vuex 中 State 状态的实现

一,前言

上篇,介绍了 vuex 的 install 插件安装逻辑,包含以下几个点:

  • 创建 vuex 插件目录;

  • 模块化设计;

  • 实现插件安装install时store实例混入逻辑;

  • 混入效果测试;

本篇,继续介绍 Vuex 中 State 状态的实现;

二,前文回顾

上一篇提到,当外部执行`Vue.use(Vuex)`时,
会调用 Vuex 对象上的 install 方法进行插件安装,
通过 `Vue.mixin` 全局混入的方式,将`new Vue`(根组件)时注入的 store 容器实例,
在 beforeCreate 生命周期,即组件创建前,混入到所有组件中,为所有组件添加 store 属性;

这样就实现了 store 容器实例的全局混入;

在页面中使用 Vuex 时:

// src/App.vue

state、getters、commit、dispatch 这些方法均来自 store 实例

三,创建 Store 类中的 State 状态

当 时,传入了一个配置对象:

// 实例化容器容器:Vuex.Store
const store = new Vuex.Store({state,mutation,actions});

所以,在 Store 类的构造方法中,需要有一个配置对象 options 作为入参:

// src/vuex/store.js

// Vuex 的容器
export class Store {
  constructor(options) { // options:{state, mutation, actions}
    const state = options.state; // 获取 options 选项中的 state 对象
  }
}

在 Vuex 中,state 中的状态要求是响应式的,即数据变化可以触发更新的视图;

而当前 Store 类中的 state 是死值,并不具备响应式;

通过点击页面中的按钮,直接修改 $store 中的 State 值,页面是不会更新的;

视图没有跟进的原因:因为 num 并不是响应式数据,不会进行依赖收集,数据变化后不会更新;

四,实现 State 状态的响应式

实现 State 数据的响应式,可以将 State 数据放到 vue 的 data 中,借助 Vue 的响应式实现:

// src/vuex/store.js

export class Store {
  constructor(options) { // options:{state, mutation, actions}
    const state = options.state;  // 获取 options 选项中的 state 对象

    // 响应式数据:new Vue({data})
    this._vm = new Vue({
      data: {
        // 在 data 中,默认不会将以$开头的属性挂载到 vm 上
        $$state: state // $$state 对象将通过 defineProperty 进行属性劫持
      }
    })
  }
  get state() { // 对外提供属性访问器:当访问state时,实际是访问 _vm._data.$$state
    return this._vm._data.$$state
  }
}

这里有一个技巧:在 Vue 中,以$开头的属性是内部的,默认不会被挂载到 vm 上的;
即不能通过 vm.$$state 获取,只能通过 _vm._data.$$state 访问,而 _data 是素有属性;

当外部通过 store.state 获取状态对象时,相当于拿到了 ,get state()是 ES6 语法属性访问器,相当于 Object.defineProperty({}) 中的 getter ;

// todo _data 相关知识可联动 Vue2.x 源码的《数据代理实现》

总结:
vuex 中 state 状态的响应式是借助了 Vue 来实现的;

响应式数据在页面渲染时会进行依赖收集,
当 store 中的 state 状态改变时,就会触发视图的更新操作;

五,结尾

本篇,介绍了 Vuex 中 State 状态的实现,主要涉及以下几个点:

  • 创建 Store 类中的 State 状态;

  • 借助 Vue 实现 State 状态的响应式;

下一篇, Vuex 中 getter 的实现;