vue3从精通到入门11:高级侦听器watchEffect

使用 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,并明确指定其类型为 numberwatchEffect 在其回调函数内部访问了 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 函数可能更适合你的需求。

相关推荐
Momo__41 分钟前
Vite 8.1 打包开发模式——10000 组件冷启动 15 倍,"No Bundle Dev" 七年后被自己终结
前端·vue.js·vite
YHL43 分钟前
🤖 Agent 智能体开发实战 · 第一课:Tool Use —— 让大模型自动干活
前端·javascript·人工智能
Monki1 小时前
AI 规范式 UI 设计,一键批量出页,高效落地不翻车
前端
山河木马1 小时前
渲染管线-计算得到gl_FragColor(片元着色器)之后续GPU流程
前端·webgl·计算机图形学
不想说话的麋鹿1 小时前
「项目实战」我用 Codex + GPT-5.5 + Trellis "氛围编程",独立做了一个情侣厨房小程序
前端·agent·全栈
接着奏乐接着舞。2 小时前
【2026年7月最新】69道RAG面试题
前端·人工智能·后端·aigc·embedding·rag
以和为贵2 小时前
前端也能搞懂 Agent:从 Function Calling 到自主编排
前端·人工智能·架构
风止何安啊2 小时前
🚦 前端并发请求 “交通管制”:别让你的接口堵成早高峰
前端·javascript·面试
J船长2 小时前
扫盲烂笔头:A 记录、CNAME 的作用, Nginx的用途,为啥叫反向代理
前端
妙码生花3 小时前
从 PHP 到 AI + Golang,程序员自救转型手记(二十六):icon 组件封装
前端·vue.js·typescript