watchEffect

在处理复杂异步逻辑时,Vue 3 的 watchEffect 相比传统的 watch 具有以下优势:

1. 自动追踪依赖

watchEffect 会自动收集其回调中使用的所有响应式依赖,无需手动指定监听源:

import { ref, watchEffect } from 'vue';

const count = ref(0);
const double = ref(0);

watchEffect(() => {
  // 自动追踪 count 的变化
  double.value = count.value * 2;
  // 可以直接在回调中编写异步逻辑
  fetchData(count.value);
});

// 无需显式指定监听源
count.value++; // 触发 watchEffect

2. 副作用清理机制

watchEffect 的回调会返回一个清理函数,用于在副作用重新执行或组件卸载前清理资源(如取消请求):

watchEffect((onCleanup) => {
  const controller = new AbortController();
  
  fetch(`/api/data?param=${count.value}`, {
    signal: controller.signal
  })
    .then(response => response.json())
    .then(data => {
      // 确保数据在请求未被取消时才更新
      if (!isAborted) {
        result.value = data;
      }
    })
    .catch(err => {
      if (err.name !== 'AbortError') {
        console.error(err);
      }
    });
  
  // 清理函数:在下一次副作用执行前或组件卸载时调用
  onCleanup(() => {
    controller.abort(); // 取消未完成的请求
  });
});

3. 立即执行与懒执行

watchEffect 默认会立即执行一次回调(相比 watch 的 immediate: true 更简洁),适合需要初始化的异步操作:

// 立即执行一次,之后依赖变化时再次执行
watchEffect(() => {
  console.log('Effect running');
});

若需要懒执行(类似 watch 默认行为),可使用 watchPostEffect 或 watchSyncEffect

4. 简化复杂逻辑

对于涉及多个依赖的复杂异步操作,watchEffect 能避免手动维护依赖数组:

const userId = ref(1);
const searchQuery = ref('');

watchEffect(() => {
  // 同时追踪 userId 和 searchQuery 的变化
  fetchUser(userId.value, searchQuery.value);
});

5. 与组合式 API 深度集成

在 Vue 3 的组合式 API 中,watchEffect 能更好地组织逻辑复用和状态管理:

// 在自定义组合函数中使用 watchEffect
export function useFetchData(initialUrl) {
  const data = ref(null);
  const loading = ref(false);
  const error = ref(null);
  const url = ref(initialUrl);
  
  watchEffect(async (onCleanup) => {
    loading.value = true;
    error.value = null;
    
    const controller = new AbortController();
    onCleanup(() => controller.abort());
    
    try {
      const response = await fetch(url.value, { signal: controller.signal });
      data.value = await response.json();
    } catch (err) {
      if (err.name !== 'AbortError') {
        error.value = err.message;
      }
    } finally {
      loading.value = false;
    }
  });
  
  return { data, loading, error, setUrl: (newUrl) => url.value = newUrl };
}

何时选择 watchEffect 而非 watch

场景 watchEffect watch
自动追踪依赖 ✅(无需指定依赖) ❌(需显式指定监听源)
需要立即执行副作用 ✅(默认立即执行) ❌(需设置 immediate: true
复杂的异步清理逻辑 ✅(内置 onCleanup ❌(需手动处理)
监听多个响应式变量 ✅(自动收集所有依赖) ❌(需分别监听或合并依赖)
仅在依赖变化时执行(非立即执行) ❌(需使用 watchPostEffect ✅(默认行为)

总结

watchEffect 通过自动依赖追踪内置清理机制立即执行特性,大幅简化了复杂异步逻辑的管理。对于需要响应多个状态变化的场景,或需要自动清理副作用的异步操作(如网络请求、定时器),watchEffect 是更优选择。而传统的 watch 则在需要精确控制监听源和监听深度时更具优势。

关键差异对比

特性 watchEffect watch
自动追踪依赖 ✅ 自动收集所有响应式依赖 ❌ 必须手动指定监听源
监听计算属性变化 ✅ 自动追踪计算属性依赖 ✅ 但需显式监听计算属性本身
获取变化前后的值 ❌ 只能获取当前值 ✅ 可访问新旧值 (newVal, oldVal)
深度监听 ❌ 仅浅层追踪 ✅ 支持 deep: true
初始执行 ✅ 默认立即执行 ❌ 默认惰性执行(需 immediate: true

你可能感兴趣的:(#,vue3,vue.js,前端,javascript)