假设在根组件用 dispatch 触发一个异步的 Action

async created() {
    await this.$store.dispatch(`base/info/get`)
},

在路由组件里 watch 数据

computed: {
    ...mapGetters({
        $$info: 'base/info/get'
    })
},
watch: {
    $$info(val) {
        console.log(val)
    }
}

刷新页面, 这时候会出现有时候能触发 watch, 有时候又不触发, 这到底是什么原因呢?

看 vue 的源代码:
https://github.com/vuejs/vue/blob/dev/src/core/instance/state.js#L48-L62

export function initState (vm: Component) {
  vm._watchers = []
  const opts = vm.$options
  if (opts.props) initProps(vm, opts.props)
  if (opts.methods) initMethods(vm, opts.methods)
  if (opts.data) {
    initData(vm)
  } else {
    observe(vm._data = {}, true /* asRootData */)
  }
  if (opts.computed) initComputed(vm, opts.computed)
  if (opts.watch && opts.watch !== nativeWatch) {
    initWatch(vm, opts.watch)
  }
}

我们可以看到, computed 是早于 watch 的, 那么我们就大概能理解上面是什么原因造成的了

当执行到 computed 时, 已经取到 ajax 返回的数据, 那么将 watch 不到 $$info 的变化, $$info 的数据已经是 ajax 的返回值

当执行到 computed 时, 取到的是 vuex 的默认值, 那么将 watch 得到 $$info 的变化, $$info 的值是 vuex 的默认值变化成 ajax 加载完成后返回的值

这一切就取决于 ajax 的加载速度, 但是 ajax 的加载速度是不可控的, 要解决这个问题, 就只能在 mounted 里再加一段代码

computed: {
    ...mapGetters({
        $$info: 'base/info/get'
    })
},
watch: {
    $$info(val) {
        // 如果组件加载完成时, 还没有取到$$info的值, 那么从这里执行相关方法
        this.someMethods(val)
    }
},
mounted() {
    // 如果组件加载完成时, 已经取到$$info的值, 那么从这里执行相关方法
    if (this.$$Info) {
        this.someMethods(this.$$Info)
    }
},
methods: {
    someMethods(info) {
        console.log(info)
    }
}