Vue3中watch和watchEffect的使用
1. watch
1.1. 基本用法一:监视ref定义的响应式数据-[基本类型],直接写数据名字,监视的是value的值
<template>
<h2>sum: {{ sum }}</h2>
<button @click="add">add</button>
</template>
<script lang="ts" setup>
import { ref, watch, reactive, watchEffect } from 'vue';
let sum = ref(0);
const add = () => {
sum.value++;
};
//解除监视
const stopWatch = watch(sum, (newVal, oldVal) => {
console.log('sum变化了:', newVal, oldVal);
if(newVal >= 10) {
stopWatch();
console.log('解除了监视');
}
})
</script>
1.2. 基本用法二:监视ref定义的响应式数据-[对象类型],监视的是地址值,如果想要对象内部的数据,要开启深度监视[deep: true]
- 没有加deep: true,默认是浅层监视,加上deep: true,开启深度监视,监视person.value的地址值和内部的数据
- immediate: true,默认是false,开启后,会立即执行一次回调函数
<template>
<h2>person: {{ person }}</h2>
<button @click="person.name += '~'">add-name</button> |
<button @click="person.age++">add-age</button> |
<button @click="changePerson">changePerson</button>
</template>
<script lang="ts" setup>
import { ref, watch, reactive, watchEffect } from 'vue';
let person = ref({
name: '张三',
age: 18
})
// 没有加deep: true,默认是浅层监视,只监视person.value的地址值,只有 person.value变化了才会触发
const changePerson = () => {
person.value = {name: '李四', age: 20}
}
// 加上deep: true,开启深度监视,监视person.value的地址值和内部的数据
watch(person, (newVal, oldVal) => {
console.log('person变化了:', newVal, oldVal);
}, { deep: true , immediate: true})
</script>
1.3. 基本用法三:监视reactive定义的响应式数据,默认开启了深度监视,而且无法关闭深度监视
<template>
<h2>person2: {{ person2 }}</h2>
<button @click="person2.name += '~'">add-name</button> |
<button @click="person2.age++">add-age</button> |
<button @click="person2.job.salary++">add-salary</button> |
<button @click="changePerson2">changeperson2</button>
</template>
<script lang="ts" setup>
import { ref, watch, reactive, watchEffect } from 'vue';
let person2 = reactive({
name: '张三',
age: 18,
job: {
salary: 20
}
})
const changePerson2 = () => {
// person2= {name: '李四', age: 20}
Object.assign(person2, {name: '李四', age: 20})
}
// 地址没有变,没有真正的替换,只是重新分配了属性值
watch(person2, (newVal, oldVal) => {
console.log('person2变化了:', newVal, oldVal);
})
</script>
1.4. 基本用法四:监视ref或reactive定义的【对象类型】数据中的某个属性,注意点如下:
- 若该属性值不是【对象类型】,需要写成函数形式。
- 若该属性值是依然是【对像类型】,可直接编,也可写成函数,建议写成函数。
- 结论:监视的要是对象里的属性,那么最好写函数式,注意点:若是对象监视的是地址值,需要关注对象内部,需要手动开启深度监视。
<template>
<h2>Person3: {{ person3 }}</h2>
<button @click="person3.name += '~'">add-name</button> |
<button @click="person3.age++">add-age</button> |
<button @click="changePerson3">changePerson3</button>
</template>
<script lang="ts" setup>
import { ref, watch, reactive, watchEffect } from 'vue';
let person3 = reactive({
name: '张三',
age: 18,
job: {
salary: 20
}
})
const changePerson3 = () => {
// person3.job = {salary: 30}
person3.job.salary = 30
}
// 监视person3中的job属性,该属性是对象类型,可以直接写,也可以写函数, 推荐写函数:() => person3.job
// (不写函数,[person3.job = {salary: 30}]整体变化会监视不到)
watch(() => person3.job, (newVal, oldVal) => {
console.log('person3变化了:', newVal, oldVal);
}, { deep: true })
</script>
1.5. 基本用法五:情况五:监视上面几种情况的多个数据:
<template>
<h2>person2: {{ person2 }}</h2>
<button @click="person2.name += '~'">add-name</button> |
<button @click="person2.age++">add-age</button> |
<button @click="person2.job.salary++">add-salary</button> |
<button @click="changePerson2">changeperson2</button>
<h2>Person3: {{ person3 }}</h2>
<button @click="person3.name += '~'">add-name</button> |
<button @click="person3.age++">add-age</button> |
<button @click="changePerson3">changePerson3</button>
</template>
<script lang="ts" setup>
import { ref, watch, reactive, watchEffect } from 'vue';
let person2 = reactive({
name: '张三',
age: 18,
job: {
salary: 20
}
})
let person3 = reactive({
name: '张三',
age: 18,
job: {
salary: 20
}
})
const changePerson3 = () => {
// person3.job = {salary: 30}
person3.job.salary = 30
}
watch([() => person2.name, person3.job], (newVal, oldVal) => {
console.log('多个数据变化了:', newVal, oldVal);
}, { deep: true })
</script>
监视的person2.name, person3.job
的属性发生变化,console.log('多个数据变化了:', newVal, oldVal);就会执行,点击其他不执行,而且会合并到同一个数组里
2.watchEffect
立即运行一个函数,同时响应式地追踪其依赖,并在依赖更改时重新执行该函数,不需要手动传入要监视的数据,会自动收集依赖,只要回调函数中用到了响应式数据,就会自动收集依赖
<template>
<h2>Person3: {{ person3 }}</h2>
<button @click="person3.name += '~'">add-name</button> |
<button @click="person3.age++">add-age</button> |
<button @click="changePerson3">changePerson3</button>
</template>
<script lang="ts" setup>
import { ref, watch, reactive, watchEffect } from 'vue';
let person4 = reactive({
name: '张三',
age: 18,
job: {
salary: 20
}
})
let changePerson4 = () => {
person4.job.salary = 30
}
watchEffect(() => {
// 用到了哪些属性,那就监视哪些属性,当这些属性变化时,就会重新执行这个函数
const x1 = person4.name
const x2 = person4.job.salary
console.log('watchEffect:', x1, x2)
})
</script>
用到了[person4.name, person4.job.salary]
属性,那就监视哪些属性,当这些属性变化时,就会重新执行这个函数
3.watch对比watchEffect
- 都能监听响应式数据的变化,不同的是监听数据变化的方式不同
- watch:要明确指出监视的数据
- watchEffect:不用明确指出监视的数据(函数中用到哪些属性,那就监视哪些属性)
4.Vue3中的watch只能监视以下四种数据:
- ref定义的数据.
- reactive定义的数据.
- 函数返回一个值
- 一个包含上述内容的数组.