watch监视的四种类型

  1. ref定义的基本数据
  2. ref定义的对象类型
  3. reactive定义的数据
  4. 函数的返回值(getter)
  5. 包含上述内容的数组

监视ref

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<script setup lang="ts">

import { watch, ref } from 'vue';
let sum = ref(0);
const stopWatch = watch(sum, (newValue, oldValue) => { //导入的变量含义只和顺序有关(value0, value1)同效,如果只导入一个(value0),value0就相当于newValue
console.log(`Sum changed from ${oldValue} to ${newValue}`);
if(newValue >= 5){ // newValue大于等于5后停止监视
stopWatch();
}
});

function addSum() {
sum.value += 1;
}

</script>

监视ref定义的对象

监视对象和监视ref的基本语法没什么区别,重要的是watch后面的一个配置项。

要注意的是,如果没有添加任何配置项,仅仅改变对象的属性不会被监视到。只有改变整个对象的值才会被监视到。如果要让改变对象的属性也能被监视到,就需要添加一个{deep:true}的配置项。

注意:{deep:true} 监视对象的属性时,属性发生改变后,传入的oldValue和newValue是一样的。这是因为在监视之前,对象的属性就已经被改变了,这时不管如何监视,都已经找不到旧值了。那为什么覆盖整个对象时oldValue可以被监视到?可以这样理解:覆盖整个对象时,它在内存里创建了一个新的地址赋值给对象,所以 旧值得以保留。而当改变属性时,并没有新的地址,而是在原地址的数据上进行的修改。这个解释放到改变普通ref变量上可以正常监视,也能说的通。

{immedia:true} 的意思是在初始化定义该对象时,也触发对其的监视。oldValue为undefined。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
<script setup lang="ts">

import { watch, ref } from 'vue';
let person = ref({
name: 'john',
age: 12
});

const stopWatch = watch(person, (newValue, oldValue)=> {
console.log('person changed:', newValue, oldValue);

}, {deep: true, immediate: true});

function changName(){
person.value.name += 'mary';
}
function changAge(){
person.value.age += 1;
}

function changeALl(){
person.value = {
name: 'newName',
age: 20
};
}

</script>

监视reactive

使用方法与ref相比除了不需要使用.value基本没有区别。

但是需要注意的是,reactive定义的对象不能直接用等号覆盖,必须要使用Object.assign来改值。这就导致覆盖reactive对象时实际上并没有给这个对象创建一个新的地址,而是使用一个函数将对象的值一个一个改变,这就导致oldValue与newValue是一致的。

还有一个区别是监视reactive时,是默认开启{deep:true}的,而且是无法关闭的。这对reactive管理深层次属性的特性有帮助。

监视对象中的属性

如果直接写

1
2
3
4
watch(person.name, (newName, oldName) => {
console.log(`Name changed from ${oldName} to ${newName}`);
});

是会报错的。

监视对象的属性需要使用箭头函数的形式。

1
2
3
4
watch(() => person.name, (newName, oldName) => {
console.log(`Name changed from ${oldName} to ${newName}`);
});

同时,如果要监视的属性也是对象,需要启用deep才能监视到内部的属性。

监视数组

只需要在监视对象的参数上用一个[]将所有要监视的对象括起来就可以了。

就像这样

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
<script setup lang="ts">

import { watch, reactive, ref } from 'vue';

let test = ref("Hello World");

let person = reactive({
name: 'John Doe',
age: 30,
car: {
model: 'Toyota',
year: 2020,
}
})

watch([() => person.name, () => person.car], (newName, oldName) => {
console.log(oldName, '->', newName);
}, {deep : true});

function updateName() {
person.name = 'Jane Smith';
}
function updateCar() {
person.car = { model: 'Ford', year: 2021 };
}
function updateCarModel() {
person.car.model = 'Honda';
}


</script>

watchEffect

是一个自动监视的函数。何为自动?就是不需要自己指出监视哪些变量,只要你用到了这个对象,他就会帮你自动监视。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<script setup lang="ts">

import { ref, watchEffect} from 'vue';

let num = ref(0);
watchEffect(() => {
console.log(`num is: ${num.value}`);
if(num.value > 5) {
num.value = 0;
}
});
function updateNum() {
num.value++;
}

</script>

有点强