在上一篇博文中讲的是 watch函数的使用以及踩坑,但是在使用过程中我们可以感觉的到并不是很方便,既要指定需要监听的属性,又要指明监听的回调,而且监听对象存在多种不同类型:例如变量,数组,函数,数组中包含函数等等,所以 Vue3 提供了一个新的 API -- watchEffect 来解决这些问题
watchEffect 与 watch 的区别
首选需要明确的是 watchEffect 也是用来监听数据变化的,但是和 watch 存在很大不同。
第一点:watchEffect 不需要指定监听的属性,而是直接触发监听的回调函数
watchEffect(() => {
console.log('watchEffect监听被触发了');
})
可以看到,当我的页面刷新之后,watchEffect 在初始化时会被直接触发,相当于 watch 中配置的immediate: true
第二点:watchEffect 回调函数中不接收 newValue 和 oldValue 的形参
其实我们也可以想得到,我都没有指定监听的属性,我去哪里拿值呢?
watchEffect((a,b,c,d) => {
console.log(a,b,c,d,'watchEffect监听被触发了');
})
从控制台打印的参数可以发现,除了第一个参数存在,其他的都是undefined。且第一位形参还是一个底层函数,并不是一个可以使用的值。
第三点:watchEffect 在进行深度监测时并不需要进行配置 deep: true
案例参考下面 watchEffect 函数监听复杂类型数据的案例
watchEffect 函数的使用
经过上面描述的与 watch 的区别,我们大致了解了 watchEffect 函数,那么他到底是怎么实现响应式的呢?
监听基础数据
let sum = ref(0);
watchEffect(() => {
let x = sum.value;
console.log("watchEffect监听被触发了");
});
我们通过 ref 函数定义了一个基础数据类型的响应式 ,然后在 watchEffect 函数中访问该响应式数据,最后我们惊奇的发现,除了初始化时监听的一次之外,当我在点击按钮之后,该 watchEffect 还会触发一次。
如果换成复杂类型的数据会怎么办呢?通过 reactive 函数定义了一个深层嵌套响应式对象,然后访问其中的某个属性
<template>
<p>
工作:{{ person.job.j1.work }} 工资:{{ person.job.j1.salary }}
</p>
<button @click="person.job.j1.salary++">涨薪</button>
</template>
let person = reactive({
name:'al',
job: {
j1: {
work: "前端",
salary: 1,
},
},
});
watchEffect(() => {
let y = person.job.j1.salary
console.log("watchEffect监听被触发了");
});
然后我们发现,它和上面的例子最终的展示效果是一样的,初始化监听一次,按钮触发后继续监听,这也表示了 watchEffect 函数会自动实现深层监听,对应上面的 第三点区别
这个时候我们对于 watchEffect 函数的基本使用就已经完成了,就是这么简单。
总结
watch:
- 既要指明监听的属性,
- 也要指明监听的回调,
- 且回调形参存在新值和旧值两个参数
- 深度监听在监听完整对象时会默认开启,但是在监听深度嵌套对象中某个值为对象的属性时,需要手动开启。
watchEffect:
- 不用指明监听的属性
- 需要指明监听回调
- 但是回调中不接收形参
- 默认可以进行深度监听
watchEffect 的套路是:不用特定指明监听哪个属性,只要在回调函数中用到了那个属性,watchEffect 就是自动监听哪个属性的变化,如果数据变化了,则直接重新执行回调。如果存在很复杂的逻辑需要处理,那使用 watchEffect 无疑是非常方便的,不然我们还需要通过 watch 一个个监听然后去处理,即分散了逻辑,也增加了工作量。
watchEffect 有点像 computed,但是存在区别:
computed 关注的是值(回调函数的返回值),所以必须要有返回值
但是 watchEffect 和 watch 注重的是过程(回调函数的函数体逻辑),所以不需要写返回值