Vuex 原理揭秘

240 阅读1分钟

实例能访问到$store的原理

大家看代码的几个高亮部分,核心原理就是,应用了Vue.mixin这个Api的功能

// 如果Vue在window上,直接install
if (!Vue && typeof window !== 'undefined' && window.Vue) {
  install(window.Vue)
}

export function install (_Vue) {
  if (Vue && _Vue === Vue) {
    if (__DEV__) {
      console.error(
        '[vuex] already installed. Vue.use(Vuex) should be called only once.'
      )
    }
    return
  }
  Vue = _Vue
  // 调用Vue
  applyMixin(Vue)
}

export default function (Vue) {
  const version = Number(Vue.version.split('.')[0])

  if (version >= 2) {
    // 把vueInit混入beforeCreate的生命周期,这里的意思就是后面每个Vue的实例创建都会调用vueInit
    Vue.mixin({ beforeCreate: vuexInit })
  } else {
    // override init and inject vuex init procedure
    // for 1.x backwards compatibility.
    const _init = Vue.prototype._init
    Vue.prototype._init = function (options = {}) {
      options.init = options.init
        ? [vuexInit].concat(options.init)
        : vuexInit
      _init.call(this, options)
    }
  }

  /**
   * Vuex init hook, injected into each instances init hooks list.
   */

  function vuexInit () {
    const options = this.$options
    // store injection
    if (options.store) {
      // 这里就解释了为什么我们通过this.$store能访问到传入到Vue的store
      this.$store = typeof options.store === 'function'
        ? options.store()
        : options.store
    } else if (options.parent && options.parent.$store) {
      this.$store = options.parent.$store
    }
  }
}

Vuex的数据是怎么响应的

这里为了大家方便理解,我把源码中部分代码删减掉了,只留了一些核心代码

// 这里的state就是我们store中的state
function resetStoreVM (store, state, hot) {

  // store中state的数据放在了data中,(这里的data最终也是放入Vue.observable),把state变成一份可观察的数据
  const silent = Vue.config.silent
  Vue.config.silent = true
  store._vm = new Vue({
    data: {
      ?state: state
    },
    // 这里的的computed实际就是我们的设置的getters
    computed: {...getters}
  })
  Vue.config.silent = silent
}

我认为的:我在没有看源码之前,我自己也想了一下Vuex中的数据是怎么做到数据响应的,我想到的是Vuex的state是经过Vue.observable处理后,数据变成了响应的了。

实际上:那Vuex这里为啥要重新创建一个Vue的实例,把数据放在data上,然后data再经过Vue.observable处理,为啥要绕这么一圈呢,直接用Vue.observable不是更加简洁吗,大家看上边那段源码里有个computed,就是因为要使用vue中的computed这个功能来缓存getter的结果