Vuex | 思路篇 | 初版

790 阅读3分钟

前言

  • 本文目标:代码层面完成一个初版的vuex
  • 本文为思路篇,主要指出阶段目标,以需解决问题和解决思路的角度讲解原理,文末附上具体实现文章链接,建议两个tab页同步对比理解
完成功能
  • vuex管理全局数据,每个组件均共享同一数据
  • vuex数据的改变同样会触发视图更新(前提是在页面上被使用,不理解为什么建议阅读拙作(vue1.0版)数据观测 依赖收集
  • 单一数据流管理:data-》actions-》mutations-》data
第二版待完成功能
  • vuex数据模块化
  • vuex插件机制
  • 辅助函数map系列(mapState、mapGetters、mapMutations、mapActions)

img

第一阶段:实现全局数据管理

先看使用
## store.js 
state: {
    count: 100
  }, 
## App.vue
<div id="app">
    {{$store.state.count}}
</div>
核心问题
  • 如何使得每个组件上都有$store属性
解决思路
  • 采用mixin+深度遍历的方式
    • mixin中使用beforeCreate钩子,这样就可以在每个组件中执行一段逻辑
    • 逻辑如下:判断是否为根组件,即$options(用户传递vue的对象)上有无store
      • 是,则挂载$store属性为store
      • 否,挂载store为父级的store为父级的store属性

第二阶段:实现数据劫持,vuex数据改变也会触发视图更新

核心问题
  • 此时只是相当于定义了一个全局属性,问题是根本未被vue托管(即未放置在data属性中),数据改变不会触发视图更新
解决思路
  • 既然插件中可以获取到vue的构造(install方法的参数),那就直接new Vue然后将state挂载到data上即可
    • 注意,此时因为state是对象,也就是引用传递,即共用同一块地址值,所以改变store上的state属性也会触发data中的state的改变,从而视图更新

注意:可以看到,vuex的实现原理就是new Vue,这是vuex强依赖vue的原因,也是与redux最大的不同

第三阶段:实现getters

先看使用
## store.js 
getters: {
    value(state){
      return state.count + 100
    }
}, 
## App.vue
  <div id="app">
    {{$store.state.count}}
    {{$store.getters.value}}
  </div>
核心问题:
  • 实现getters的取值正常,即函数返回值为其取值
  • 实现更改getters触发视图更新
核心思路:
  • 初始化时为每个getter定义defineProerty,取值时执行其对应函数,将函数返回值返回
  • 借用vue中的computed,将getter定义在vm上;
    • 其实vuex中的getters就是对应vue的compouted,一是计算属性,二是可缓存
    • 取值的逻辑也得改为直接从vm实例上获取 这样才能实现依赖收集,不理解的话建议阅读拙作vue|源码篇|watch及computed的实现

第四阶段:实现更改数据流程

先来看看vuex官网的流程图

vuex

由state出发,我们已经实现了state-》Vue components这个render阶段,我们可以发现,在vue中提倡组件中触发actions,再由actions去触发mutations更改state,即达到更改数据单一入口的设计(mutations)

### store.js
 mutations: {
    add(state){
      state.count += 1;
    }
  },
  
  actions: {
    add({commit}){
      commit('add')
    }
  },
  
  ### App.vue
  methods: {
    clickMe(){
      this.$store.dispatch('add')
    }
  }
核心问题
  • 实现api
  • this问题,在actions中执行commit方法,若不处理其this将指向undefined
解决思路
  • store类上定义commit、dispatch方法,分别执行store上的mutation、action
  • 考虑原型链,在构造中再次定义commit、dispatch方法,内部以call执行原型上的commit/dispatch绑定this

具体实现链接

Vuex | 具体实现篇 | 基础实现