在 Vue 3 中,监听数据变化主要依赖 watch
和 watchEffect
两个 API,它们都属于 Composition API 的一部分。以下是详细的用法和区别:
一、watch
的基本用法
作用:显式监听特定数据源,在数据变化时执行回调函数。
1. 监听单个数据源
javascript
复制
import { ref, watch } from 'vue'; const count = ref(0); // 监听 ref watch(count, (newVal, oldVal) => { console.log(`count变化: ${oldVal} → ${newVal}`); });
2. 监听 reactive 对象的属性
javascript
复制
import { reactive, watch } from 'vue'; const state = reactive({ user: { name: 'Alice', age: 30 } }); // 监听对象属性(需用 getter 函数) watch( () => state.user.age, (newVal, oldVal) => { console.log(`年龄变化: ${oldVal} → ${newVal}`); } );
3. 监听多个数据源
javascript
复制
const a = ref(1); const b = ref(2); watch([a, b], ([newA, newB], [oldA, oldB]) => { console.log(`a: ${oldA}→${newA}, b: ${oldB}→${newB}`); });
4. 深度监听(deep)
默认情况下,watch
是浅层监听。对嵌套对象需开启 deep: true
:
javascript
复制
watch( () => state.user, (newUser) => { console.log('用户信息变化(包括嵌套属性):', newUser); }, { deep: true } );
5. 立即执行(immediate)
在监听开始后立即触发回调:
javascript
复制
watch( count, (newVal) => { console.log('初始值:', newVal); }, { immediate: true } );
二、watchEffect
的用法
作用:自动跟踪依赖,并在依赖变化时立即执行副作用函数。
1. 基本使用
javascript
复制
import { ref, watchEffect } from 'vue'; const count = ref(0); // 自动追踪 count 的变化 watchEffect(() => { console.log('当前count值:', count.value); });
2. 自动聚合依赖
无需手动指定依赖,函数内使用的响应式变量会被自动追踪:
javascript
复制
const a = ref(1); const b = ref(2); watchEffect(() => { console.log('a + b =', a.value + b.value); }); // 修改 a 或 b 都会触发
3. 清理副作用
通过返回一个函数来清理副作用(如定时器、事件监听):
javascript
复制
watchEffect((onCleanup) => { const timer = setInterval(() => { console.log('每秒执行'); }, 1000); onCleanup(() => clearInterval(timer)); });
三、watch
vs watchEffect
特性 | watch | watchEffect |
---|---|---|
依赖指定 | 显式指定数据源 | 自动追踪回调内的响应式依赖 |
初始执行 | 默认不执行(可配置 immediate ) | 立即执行 |
适用场景 | 需要精确控制监听的数据源 | 依赖变化时自动执行聚合逻辑 |
深度监听 | 需手动开启 deep: true | 自动追踪嵌套属性(类似 deep) |
四、停止监听器
通过调用 watch
或 watchEffect
返回的函数来停止监听:
javascript
复制
const stop = watchEffect(() => { /* ... */ }); // 停止监听 stop();
在组件卸载时自动停止:
javascript
复制
import { onUnmounted } from 'vue'; setup() { const stop = watchEffect(() => { /* ... */ }); onUnmounted(stop); }
五、实用场景示例
1. 搜索输入防抖(watch)
javascript
复制
const searchQuery = ref(''); let timeoutId; watch(searchQuery, (newQuery) => { clearTimeout(timeoutId); timeoutId = setTimeout(() => { fetchResults(newQuery); }, 500); });
2. 自动保存表单(watchEffect)
javascript
复制
const form = reactive({ title: '', content: '' }); watchEffect((onCleanup) => { // 自动追踪 form.title 和 form.content const autoSave = setTimeout(() => { saveToServer(form); }, 3000); onCleanup(() => clearTimeout(autoSave)); });
六、注意事项
-
避免无限循环:在监听回调中修改被监听的数据可能导致循环,需谨慎。
-
性能优化:避免过度使用
deep: true
,尤其是大型对象。 -
异步操作:在回调中进行异步操作时,使用
onCleanup
清理未完成的请求。
掌握这些技巧后,你可以更灵活地利用 Vue 3 的响应式系统构建高效应用!