Vue3中Vue.use()在vuex中的使用(源码解析)

433 阅读1分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第1天

Vue2与Vue3中的use函数的区别

我们知道Vue2是配置项api, Vue3是组合式api,比如Vuex插件
在Vue2中我们是通过this.$store获取的store实例。
在Vue3中,通过useStore获取的store实例。

<script>
import { useStore } from 'vuex'

export default {
  setup () {
    const store = useStore()
  }
}

回顾Vue2的Vue.use()

Vue.use = function (plugin: Function | Object) {
    const installedPlugins = (this._installedPlugins || (this._installedPlugins = []))
    if (installedPlugins.indexOf(plugin) > -1) {
      return this
    }

    // additional parameters
    const args = toArray(arguments, 1)
    args.unshift(this)
    if (typeof plugin.install === 'function') {
      plugin.install.apply(plugin, args)
    } else if (typeof plugin === 'function') {
      plugin.apply(null, args)
    }
    installedPlugins.push(plugin)
    return this
  }

plugin必须是一个对象或者函数

  • 如果是对象,必须有install方法
  • 如果是函数,那么就当做install被执行
  • installedPlugins数组用来判断是否已经安装过该插件
  • install函数的第一个参数是Vue的实例

Vue3的用法

 use(plugin: Plugin, ...options: any[]) {
        if (installedPlugins.has(plugin)) {
          __DEV__ && warn(`Plugin has already been applied to target app.`)
        } else if (plugin && isFunction(plugin.install)) {
          installedPlugins.add(plugin)
          plugin.install(app, ...options)
        } else if (isFunction(plugin)) {
          installedPlugins.add(plugin)
          plugin(app, ...options)
        } else if (__DEV__) {
          warn(
            `A plugin must either be a function or an object with an "install" ` +
              `function.`
          )
        }
        return app
      }

Vue3和Vue2实现唯一区别是install函数的第一个参数

  • Vue2是Vue函数的实例
  • Vue3是通过createAppContext创造出来的content上的app

如何获取vuex的store实例

vue2中如何将store实例挂载到组件的this.$store上

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

  if (version >= 2) {
    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 = typeof options.store === 'function'
        ? options.store()
        : options.store
    } else if (options.parent && options.parent.$store) {
      this.$store = options.parent.$store
    }
  }
}

vue2中传进来的是vue的实例。
beforeCreate钩子函数会执行vuexInit函数,相当于Vue在初始化时候,会先执行一次vuexInit函数。
这个时候每个组件的this.$store获取到了store的实例。

在Vue3中如何存储和获取store实例

存储store实例

install (app, injectKey) {
    app.provide(injectKey || storeKey, this)
    app.config.globalProperties.$store = this

    const useDevtools = this._devtools !== undefined
      ? this._devtools
      : __DEV__ || __VUE_PROD_DEVTOOLS__

    if (useDevtools) {
      addDevtools(app, this)
    }
  }

storeKey默认值为'store'
其中this是Store构造函数的实例
我们可以看到我们有两种存储store实例有两个方法

  • app.provide(injectKey || storeKey, this)
  • app.config.globalProperties.$store = this

通过useStore读取store实例

当我们调用useStore函数

import { useStore } from 'vuex'

export default {
  setup () {
    const store = useStore()
  }
}

我们看下useStore源码

import { inject } from 'vue'

export const storeKey = 'store'

export function useStore (key = null) {
  return inject(key !== null ? key : storeKey)
}

我们就清楚了,在useStore函数里面,通过inject函数获取store实例。

通过this.$store访问实例

globalProperties是Vue3提供的一个全局属性对象,使我们可以通过this获取globalProperties上的属性
使用方法

export default { 
    mounted() {
        console.log(this.$store) 
    } 
}

总结

至此,我们已经梳理清楚Vue.use在Vue2和Vue3中使用方法的不同,让我们更好的理解组合式api编程的方法。