vue之watchEffect
在Options API中,我们可以通过watch选项来侦听data或者props的数据变化,当数据变化时执行某一些操作。 在Composition API中,我们可以使用watchEffect和watch来完成响应式数据的侦听。 watchEffect用于自动收集响应式数据的依赖,需要手动指定侦听的数据源。
侦听数据的变化
案例:
watchEffect传入的函数会被立即执行一次,并且在执行的过程中会收集依赖;
其次,只有收集的依赖发生变化时,watchEffect传入的函数才会再次执行;
<template>
<div>
<h2>{{name}}-{{age}}</h2>
<button @click="changeName">修改name</button>
<button @click="changeAge">修改age</button>
</div>
</template>
<script>
import { ref, watchEffect } from 'vue';
export default {
setup() {
// watchEffect: 自动收集响应式的依赖
const name = ref("why");
const age = ref(18);
const changeName = () => name.value = "kobe"
const changeAge = () => age.value++
watchEffect(() => {
console.log("name:", name.value, "age:", age.value);
});
return {
name,
age,
changeName,
changeAge
}
}
}
</script>
停止侦听
如果在某些情况下希望停止侦听,这个时候我们可以获取watchEffect的返回值函数,调用该函数即可。
const stop = watchEffect(() => {
console.log("name:", name.value, "age:", age.value);
});
const changeName = () => name.value = "kobe"
const changeAge = () => {
age.value++;
if (age.value > 25) {
stop();
}
}
比如在上面的案例中,当age达到25的时候就停止侦听。
清除副作用
在开发中我们需要在侦听函数中执行网络请求,但是在网络请求还没有达到的时候,停止了侦听器,或者侦听器/侦听函数被再次执行了。 那么上一次的网络请求应该被取消掉,这个时候我们就可以清除上一次的副作用;
在给watchEffect传入的函数被回调时,其实可以获取到一个参数:onInvalidate
当
副作用即将重新执行
或者
侦听器被停止 时会执行该函数传入的回调函数,此时我们可以在传入的回调函数中,执行一些清除工作。
const stop = watchEffect((onInvalidate) => {
const timer = setTimeout(() => {
console.log("网络请求成功~");
}, 2000)
// 根据name和age两个变量发送网络请求
onInvalidate(() => {
// 在这个函数中清除额外的副作用
// request.cancel()
clearTimeout(timer);
console.log("onInvalidate");
})
console.log("name:", name.value, "age:", age.value);
});
setup中使用ref
在setup中如何使用ref获取元素或组件?
其实非常简单,我们只需要定义一个ref对象,绑定到元素或者组件的ref属性上即可。
这里也可以用生命周期函数mounted来检测是否能正确获取到对应的dom元素。不过这里侦听函数会立即执行一次,所以先打印一个null值,后面等页面挂载完成了,搜集的依赖就再次被回调执行一次,打印真正的dom对象。
默认情况下,组件的更新会在副作用函数执行之前。
调整watchEffect执行时机
如果我们希望在第一次的时候就打印出来对应的元素呢?
这个时候就需要改变副作用函数的执行时机:默认值是pre,在元素挂载或者更新之前执行。
所以会先打印出来一个null,当依赖的title发生改变时,就会再次执行一次,打印出元素;
watchEffect(() => {
console.log(title.value);
}, {
flush: "post" // 获取组件更新完成之后的DOM
})
flush 选项还接受sync,这将强制效果始终同步触发。然而这是低效的,应该很少需要。