• 一文讲解Vuex实现原理


    前言

     对于Vuex相信大家是常用,那么Vuex作为Vue生态中最重要的一部分,专为Vue.js应用的状态管理模式,每一个 Vuex 应用的核心就是 store(仓库)。“store” 基本上就是一个容器,它包含着你的应用中大部分的状态 ( state ),并且Vuex 的状态存储是响应式的。当 Vue 组件从 store 中读取状态的时候,若 store 中的状态发生变化,那么相应的组件也会相应地得到高效更新。改变 store 中的状态的唯一途径就是显式地提交 (commit) mutation。这样可以方便地跟踪每一个状态的变化。

    原理分析

    Vuex装载分析

     这个问题实际就是问到Vuex的store是如何装载到组件中的,首先利用了Vue的插件机制使用Vue.use(Vuex)来去安装Vuex插件,那么此时会调用vuex的install方法,当调用install时此时会利用mixin机制在beforeCreate阶段去执行vuexInit。核心源码如下:

    Vue.mixin({ beforeCreate: vuexInit });
    
    • 1

     我们可以发现在beforeCreate阶段调用了vuexInit方法,我们分析一下vuexInit方法。

      /**
       * Vuex init hook, injected into each instances init hooks list.
       */
    
      function vuexInit () {
        const options = this.$options
        // store injection
        if (options.store) {
          this.$store = typeof options.store === 'function'
            ? options.store()
            : options.store
        } else if (options.parent && options.parent.$store) {
          this.$store = options.parent.$store
        }
      }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

     分析如上代码:将初始化Vue根组件时传入的store设置到this对象的$store属性上,子组件从其父组件引用$store属性,层层嵌套进行设置。在任意组件中执行 this.$store 都能找到装载的那个store对象。

    Vuex中的state与getter

     vuex的Store 会划分出 state 和 getters 两个数据区。getter是从store的state中派生出的状态。那么首先我们先看我们是如何访问state的?

      get state () {
        return this._vm._data.$$state
      }
    
    • 1
    • 2
    • 3

     当我们使用this.$store.state.xxx去获取xxx属性时,实际获取的是store挂载到_vm中store._vm.data.$$state中的数据。
     state是如何挂载上去的?我们在Store constructor找到了核心函数resetStoreVM,观察resetStoreVM的核心代码,其主要做的事情是初始化了一个vue实例_vm,由于vue的data是响应式的,所以,$$state也是响应式的,那么当我们 在一个组件实例中 对state.xxx进行 更新时,基于vue的data的响应式机制,所有相关组件的state.xxx的值都会自动更新,视图自然也会自动更新,核心代码如下:

      store._vm = new Vue({
        data: {
          $$state: state
        },
        computed
      })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

     上面所介绍的是state,那么接下来我们介绍一下getter,其核心源码也是在
    resetStoreVM中,核心源码如下:

      forEachValue(wrappedGetters, (fn, key) => {
        // use computed to leverage its lazy-caching mechanism
        // direct inline function use will lead to closure preserving oldVm.
        // using partial to return function with only arguments preserved in closure environment.
        computed[key] = partial(fn, store)
        Object.defineProperty(store.getters, key, {
          get: () => store._vm[key],
          enumerable: true // for local getters
        })
      })
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

     until.js的部分源码如下:

    /**
     * forEach for object
     */
    export function forEachValue (obj, fn) {
      Object.keys(obj).forEach(key => fn(obj[key], key))
    }
    export function partial (fn, arg) {
      return function () {
        return fn(arg)
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

     对wrappedGetters 进行处理,让getter 存储至computed对象上,对getter对象的属性进行数据劫持,当触发get时,返回store._vm[key],最后将computed挂载到vue实例上,当做计算属性。

      store._vm = new Vue({
        data: {
          $$state: state
        },
        computed
      })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    总结

    • vuex利用了vue的mixin机制,混合 beforeCreate 钩子 将store注入至vue组件实例上,并注册了 vuex store的引用属性 $store。
    • vuex的state是借助vue的响应式data实现的。getter是借助vue的计算属性computed特性实现的。

    Vue源码系列文章:

  • 相关阅读:
    端到端自动驾驶系列(一):自动驾驶综述解析
    【Linux】Centos 8 服务器部署:阿里云域名注册、域名解析、个人网站 ICP 备案详细教程
    POI、Easy Excel操作Excel
    网络层面随笔
    Python OpenCV将n×n的小图拼接成m×m的大图
    scrm系统源码该如何选择?快鲸scrm系统源码优势明显
    基于SSM框架的人力资源管理系统毕业设计源码060936
    Error response from daemon: Get https://registry-1.docker.io/v2/
    idea创建的idea项目springframework是红色的
    C++中的内存管理
  • 原文地址:https://blog.csdn.net/liu19721018/article/details/125570495