老师关于 computed 和 watch ,我没弄明白,能讲解一下吗

来源:3-11 侦测变化 - watch

小麦弥望

2021-05-11

老师,关于 watch 和 computed 我有些问题,下面是一个简单的demo

<template>
<div></div>
<button @click="change">change</button>
<div>ref1:{{ref1}}</div>
<div>ref2:{{ref2}}</div>
<div>ref3:{{ref3}}</div>
<div>ref4:{{ref4}}</div>
</template>

<script>
import { watch, computed, reactive } from 'vue'
export default {
  components: {
  },
  setup () {
    const obj = reactive({
      property: 1
    })

    const change = () => {
      obj.property++
      console.log(ref1, ref2, ref2.value, ref3, ref4, obj)
    }

    const ref1 = computed(() => {
      return {
        property: obj.property
      }
    })

    const ref2 = computed(() => obj)

    const ref3 = computed(() => {
      return {
        property: {
          property: obj.property
        }
      }
    })

    const ref4 = computed(() => {
      return {
        property: obj
      }
    })

    watch(ref1, () => {
      console.log('监听到了ref1') // 可以被监听
    })
    watch(ref2, () => {
      console.log('监听到了ref2') // 不能被监听
    })
    watch(ref3, () => {
      console.log('监听到了ref3') // 可以被监听
    })
    watch(ref4, () => {
      console.log('监听到了ref4') // 不能被监听
    })
    watch(ref2.value, () => {
      console.log('监听到了ref2.value') // 可以被监听
    })
    watch(obj, () => {
      console.log('监听到了obj') // 可以被监听
    })
    return {
      ref1,
      ref2,
      ref3,
      ref4,
      change
    }
  }
}
</script>

我困惑的是为什么 ref2 和 ref4 不能被watch监听,从demo中看,computed中的写 reactive 的属性的时候就是可以被监听的,直接写reactive就不行,但是这是为什么呢,老师能不能解答一下,或者贴一下相关的链接

我问这个问题的原因是我写了一个组件,使用watch监听一个父组件传入的option,如下所示,

    watch(() => props.option, (nextValue, proValue) => {
      init()
    })

与demo不同的是 这个option结构很复杂,是由很多的响应式对象拼接的,如果可以用 computed处理好,传入组件中统一处理就会很省事了,但是我遇见了demo中的那个问题,我没法确定什么样的 computed 可以被 watch 监听到。从demo中我找到了一些规律,但还是没弄明白为啥会这样,希望老师可以讲解一下

写回答

1回答

张轩

2021-05-12

同学你好 首先 watch 对于 reactive object 在文档中有专门的一章,建议认真阅读,因为还挺有难度的。

https://v3.vuejs.org/guide/reactivity-computed-watchers.html#watching-reactive-objects

再次,回到你的问题,我们能发现这样的规律,当你在 computed 中直接返回 obj 的时候,是不能检测到变化的。

// 比如
const ref2 = computed(() => obj);
// 而将 obj 中的某个值展开进行赋值的话,是可以检测到变化的,比如
const ref1 = computed(() => {return {property: obj.property};});
// 中等于使用reactive 上的某一个值返回了一个新的对象。
其实这和上面文档中说的是有关系的,因为当一个 computed 其中的 reactive 是对象的引用,
在对象上面赋值,
对象没有变化,所以就不会有变化了。


0
1
小麦弥望
但是还有一个让我困惑的地方,官网的意思好像是监听的对象本身是 '引用值' 时,必须把他转换成一个只有 '原始值' 的副本,才能被监听 但是在 demo 中(最后一个watch),直接在 watch 中监听 obj 是可行的,而且我并没有按官网说的转换成原始值,或者加上 { deep: true }。 这是 vue 做的优化,还是我对文档的理解有误。
2021-05-12
共1条回复

Vue3 + TS 仿知乎专栏企业级项目

带你完成前后端分离复杂项目,率先掌握 vue3 造轮子技能

3142 学习 · 2313 问题

查看课程