使用 TypeScript 和 <script setup>
语法糖结合 watchEffect
可以提供强大的类型检查和更简洁的组件逻辑。watchEffect
会自动收集其执行过程中访问到的响应式依赖,并在这些依赖变化时重新运行回调函数。
watchEffect用法
watchEffect()
跟 watch
的作用基本一致,用于监听响应性数据的变化,并根据变化做一些响应的业务逻辑。
html
<template>
<div>
<p>Count: {{ count }}</p>
<button @click="increment">Increment</button>
</div>
</template>
<script setup lang="ts">
import { ref, watchEffect } from 'vue';
// 定义响应式引用及其类型
const count = ref<number>(0);
// 使用 watchEffect 监听 count 的变化
watchEffect(() => {
console.log('watchEffect triggered');
console.log('Count is now:', count.value);
});
// 定义一个方法来增加 count 的值
const increment = () => {
count.value++;
};
</script>
我们使用了 ref<number>(0)
来创建一个初始值为 0
的响应式引用 count
,并明确指定其类型为 number
。watchEffect
在其回调函数内部访问了 count.value
,因此当 count
的值变化时,watchEffect
的回调函数会自动重新执行。
如果你想要在
watchEffect
的回调函数中访问组件的props
或其他响应式状态,并且这些状态具有复杂的类型,你可以使用 TypeScript 的接口或类型别名来定义这些状态的类型。
例如:
html
<script setup lang="ts">
import { ref, watchEffect } from 'vue';
interface User {
name: string;
age: number;
email: string;
}
const user = ref<User>({
name: 'John Doe',
age: 30,
email: 'johndoe@example.com',
});
watchEffect(() => {
console.log('User data changed:', user.value);
});
</script>
onInvalidate
清除副作用:
onInvalidate
是一个函数,它接收一个回调函数作为参数。这个回调函数会在 watchEffect
的副作用函数重新执行之前被调用,或者在组件卸载时(如果副作用函数是在 setup
函数或生命周期钩子中使用的 watchEffect
)被调用。这样,我们就可以在这个回调函数中执行必要的清理操作。
javascript
import { ref, watchEffect } from 'vue';
const count = ref(0);
watchEffect(onInvalidate => {
const timer = setInterval(() => {
console.log(`Count is: ${count.value}`);
}, 1000);
onInvalidate(() => {
clearInterval(timer);
console.log('Timer has been cleared');
});
});
在这个例子中,我们创建了一个定时器,用于每秒打印 count
的值。然后,我们使用 onInvalidate
注册了一个清理函数,当 watchEffect
的副作用函数重新执行或组件卸载时,这个清理函数会被调用,从而清除定时器。
watchEffect的使用场景
1. 监听多个响应式依赖的变化
当需要监听多个响应式数据的变化,并且没有明确的监听顺序时,watchEffect
是一个很好的选择。它会自动收集其执行过程中访问到的所有响应式依赖,并在这些依赖变化时重新运行回调函数。
javascript
import { ref, watchEffect } from 'vue';
const count = ref(0);
const name = ref('');
watchEffect(() => {
console.log(`Count: ${count.value}, Name: ${name.value}`);
});
// 当 count 或 name 发生变化时,回调函数都会重新执行
2. 异步副作用操作
当需要在响应式数据变化时执行异步操作(如 API 请求)时,watchEffect
可以很好地处理。因为 watchEffect
的回调函数是异步执行的,你可以在回调中安全地使用 async/await
。
javascript
import { ref, watchEffect } from 'vue';
const searchQuery = ref('');
watchEffect(async onInvalidate => {
const result = await fetchData(searchQuery.value);
// 处理结果...
onInvalidate(() => {
// 清理操作,比如取消请求等
});
});
3. 无需显式指定依赖项
与 watch
不同,watchEffect
不需要显式指定要监听的依赖项。它会自动收集,这使得它在某些场景下更为方便。例如,当你不确定要监听哪些依赖项,或者依赖项较多时。
javascript
import { ref, watchEffect } from 'vue';
const form = reactive({
name: '',
email: '',
password: ''
});
watchEffect(() => {
validateForm(form);
});
// 当 form 对象中的任何属性变化时,validateForm 都会被调用
4. 对副作用进行清理
当副作用函数需要执行清理操作(如取消定时器、移除事件监听器等)时,可以使用 onInvalidate
。这在 watchEffect
中是非常有用的,因为它提供了一种机制来确保在组件卸载或副作用函数重新运行之前执行必要的清理操作。
javascript
import { ref, watchEffect } from 'vue';
const count = ref(0);
watchEffect(onInvalidate => {
const timer = setInterval(() => {
console.log(count.value);
}, 1000);
onInvalidate(() => {
clearInterval(timer);
});
});
5. 初始执行回调
默认情况下,watchEffect
在组件挂载后会立即执行其回调函数一次。这可以用于执行初始的副作用操作,如初始化状态或发送初始请求。
javascript
import { ref, watchEffect } from 'vue';
const isLoaded = ref(false);
watchEffect(() => {
fetchData().then(() => {
isLoaded.value = true;
});
});
// 组件挂载后,fetchData 会被立即调用
总结
watchEffect
是一个强大的工具,它简化了对多个响应式依赖的监听,并提供了对异步操作和副作用清理的支持。当你不确定要监听哪些具体依赖项,或者需要执行初始副作用操作时,watchEffect
是一个很好的选择。然而,如果你需要更细粒度地控制依赖项的变化,或者需要更多的选项来定制侦听器行为,那么watch
函数可能更适合你的需求。