假设在根组件用 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)
    }
}

======== 2019.11.13 更新下写法 ========

data() {
    return {
        tmpWatch: null
    }
}
computed: {
    ...mapGetters({
        $info: 'base/info/get'
    })
},
mounted() {
    const tmpFn = () => {
        // 相关逻辑
        this.$info.children.forEach(item => {})
        // 如果只需要监听一次, 执行完相关逻辑后可以直接注销
        if (this.tmpWatch) this.tmpWatch()
    }
    // 如果组件加载完成时, 已经取到$info的值, 那么从这里执行相关方法
    if (this.$info) {
        tmpFn()
    // 否则通过 $watch 来监听
    } else {
        this.tmpWatch = this.$watch('$info', tmpFn)
    }
}
发表评论
1231
123123
1231
123123