理解笔记
首先需要理解watch和deep的重要概念,详见【Vue巨坑】当 watch 和 deep: true 相遇:一场由“newVal === oldVal”引发的血案
ref和reactive不一样
- 不设置deep的情况下(默认
deep: false
,但reactive不太一样是特例),在watch的第一个参数中直接放一个ref,只能监听到第一层的变化(如ref.value
的变化),修改ref.value.a
或ref.value.a.b
不会触发回调执行;而放一个reactive则能监听到任何一层,是深度的,默认效果和设置了deep: true
是一样的,如果显式设置了deep: false
,那么reactive的深层也监听不到了,只能监听到reactive.a
的变化。 - 在设置
deep: true
的情况下ref和reactive效果一样,都能监听到深层的变化(如xx.a.b的变化) - 容易出现误区的地方是(重点理解):
- 官网文档说如果给ref赋一个对象作为值,那么会给这个对象包一层reactive来实现深层响应性。所以把
ref.value
放到watch监听中的效果等同于放了一个reactive。但在<template></template>
中,ref.a.b
(其实ref.a
同理)也能响应式更新(在watch中,监听ref无法监听到ref.a.b
的变化,但其实这个时候相当于设置了() => ref.value.a.b
,即在template中使用ref.xx.xx
默认等效于watch中的() => ref.value.xx.xx
)。 - 假如说声明一个
const obj = ref({ a: { b: 1 } })
,那么在不设置deep的情况下,在watch的第一个参数中放obj
,那么只能监听到obj.value
,无法监听到obj.value.a
和obj.value.a.b
的变化;放obj.value
则可以监听到obj.value.a
和obj.value.a.b
的变化。在<template></template
中直接写obj.a.b
却可以响应式更新。(本质是对于ref而言,只能监听到ref.value
的值的变化;而reactive默认深层监听,可以监听到reactive.a.b
)
- 官网文档说如果给ref赋一个对象作为值,那么会给这个对象包一层reactive来实现深层响应性。所以把
举例
如下demo片段,obj.a.b
和obj.c
在<template></template>
中都能响应式更新
<script setup>
import { ref } from 'vue'
const obj = ref({
a: {
b: 1
},
c: 1
})
setInterval(() => {
obj.value.a.b++;
// obj.value.c++;
}, 300);
</script>
<template>
<h1>{{ obj.a.b }}</h1>
<!-- <h1>{{ obj.c }}</h1> -->
</template>
另一个例子,需要重点理解一个易错点是:
watch中监听ref
(未设置deep时),改变ref.value.a
是不会触发回调执行的!!!只有改变ref.value
才会触发,即使ref.value
是个reactive对象。
<script setup>
import { ref, watch } from 'vue'
const obj = ref({
a: {
b: 1
},
c: 1
});
const numA = ref(0);
const numB = ref(0);
setInterval(() => {
// obj.value.a.b++;
obj.value.c++;
}, 300);
// obj 是个 ref, 默认效果是 deep: false, 只能监听到 ref.value 本身的变化
// [易错点!!!] 即只有给 ref.value = {} 一个新地址的时候才能触发回调执行
watch(obj, () => {
numA.value = numA.value + 1;
});
// obj.value 是个 reactive, 默认深层, 除非显式设置 deep: false
watch(obj.value, () => {
numB.value = numB.value + 1;
});
</script>
<template>
<h1>{{ obj.a.b }}</h1>
<!-- <h1>{{ obj.c }}</h1> -->
<div>numA不会变: {{ numA }}</div>
<div>numB会变: {{ numB }}</div>
</template>
Comments NOTHING