在 Vue3 的 Composition API 中,watch 函数是构建响应式逻辑的核心工具之一。它允许你精确追踪特定响应式数据源的变化,并在变化时执行副作用代码,为复杂交互和数据流管理提供了强大支持。
基础与进阶用法:
import { ref, watch, reactive } from 'vue';
// 1. 监听单个 ref
const count = ref(0);
watch(count, (newVal, oldVal) => {
console.log(`Count changed from ${oldVal} to ${newVal}`);
});
// 2. 监听 reactive 对象的特定属性(需使用 getter 函数)
const user = reactive({ name: 'Alice', age: 30 });
watch(() => user.name, (newName) => {
console.log(`Name updated to: ${newName}`);
});
// 3. 监听多个源(数组形式)
watch([count, () => user.age], ([newCount, newAge], [oldCount, oldAge]) => {
console.log(`Count or Age changed`);
});
关键配置选项:
deep: true:深度监听对象/数组内部嵌套值的变化(监听reactive对象时默认启用)
const nestedObj = reactive({ data: { value: 1 } });
watch(() => nestedObj, (newVal) => {
console.log('Deep change detected', newVal.data.value);
}, { deep: true }); // 对 ref 或 getter 返回的对象必要
-
immediate: true:在监听器创建时立即触发回调(使用初始值)watch(count, (newVal) => { console.log('Initial or updated count:', newVal); }, { immediate: true }); -
flush: 'post':回调延迟到组件 DOM 更新后执行watch(someRef, () => { // 操作更新后的 DOM }, { flush: 'post' });
watch vs watchEffect:
watch:显式声明依赖源,仅在特定数据变化时触发。提供旧值/新值,支持惰性执行(默认不立即执行)。watchEffect:自动追踪回调内使用的响应式依赖。立即执行一次以收集依赖,无法直接获取旧值。
最佳实践与场景:
- 异步操作与清理: 在回调中执行异步任务(如 API 请求),使用
onCleanup注册清理函数取消未完成的请求,避免竞态条件。
watch(dataId, async (newId, oldId, onCleanup) => {
let cancelled = false;
onCleanup(() => cancelled = true); // 清理上一次的请求
const data = await fetchData(newId);
if (!cancelled) {
// 安全更新状态
}
});
- 性能优化: 仅监听必要数据,避免过度使用
deep。对于复杂计算,考虑结合computed。 - 停止监听:
watch返回一个停止函数,在setup()或生命周期钩子中调用可手动解除监听(组件卸载时自动停止)。
const stopWatch = watch(/* ... */);
// 需要时停止
stopWatch();
Vue3 的 watch 提供了细粒度的响应式数据监听能力。通过灵活运用其监听数据源的方式(ref、getter、数组)、合理配置选项(deep, immediate, flush),以及处理异步场景的清理机制,开发者能够高效构建响应式逻辑。理解其与 watchEffect 的区别(显式依赖 vs 自动依赖,惰性 vs 立即执行)是选择合适工具的关键。牢记在组件卸载时 watch 会自动清理,结合手动停止函数,可以有效管理资源并提升应用性能。