深入掌握 Vue3 的 watch:响应式数据监听的利器

145 阅读2分钟

在 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:自动追踪回调内使用的响应式依赖。立即执行一次以收集依赖,无法直接获取旧值。

最佳实践与场景:

  1. 异步操作与清理:  在回调中执行异步任务(如 API 请求),使用 onCleanup 注册清理函数取消未完成的请求,避免竞态条件。
watch(dataId, async (newId, oldId, onCleanup) => {
  let cancelled = false;
  onCleanup(() => cancelled = true); // 清理上一次的请求
  
  const data = await fetchData(newId);
  if (!cancelled) {
    // 安全更新状态
  }
});
  1. 性能优化:  仅监听必要数据,避免过度使用 deep。对于复杂计算,考虑结合 computed
  2. 停止监听:  watch 返回一个停止函数,在 setup() 或生命周期钩子中调用可手动解除监听(组件卸载时自动停止)。
const stopWatch = watch(/* ... */);
// 需要时停止
stopWatch();

Vue3 的 watch 提供了细粒度的响应式数据监听能力。通过灵活运用其监听数据源的方式(ref、getter、数组)、合理配置选项(deepimmediateflush),以及处理异步场景的清理机制,开发者能够高效构建响应式逻辑。理解其与 watchEffect 的区别(显式依赖 vs 自动依赖,惰性 vs 立即执行)是选择合适工具的关键。牢记在组件卸载时 watch 会自动清理,结合手动停止函数,可以有效管理资源并提升应用性能。