vue2 和 vue3 中,watch 和 watchEffect 的区别

在 Vue 2 和 Vue 3 中,watchwatchEffect 都是用于监听数据变化并执行副作用的 API,但它们在用法、监听方式、依赖追踪 等方面有显著区别,且 watchEffect 是 Vue 3 新增的 API(Vue 2 中不存在)。

1. 基本区别与存在版本

  • watch

    Vue 2 和 Vue 3 中均存在,是更传统的监听方式,需要明确指定要监听的数据源。

  • watchEffect

    仅存在于 Vue 3 中,是一种更简洁的监听方式,无需明确指定监听源,会自动追踪依赖。

2. 核心区别对比

特性 watch(Vue 2/3) watchEffect(仅 Vue 3)
监听目标 需明确指定监听的数据源(如 datacomputed 等) 无需指定,自动追踪函数内部使用的响应式数据
初始化执行 默认不执行,需通过 immediate: true 配置才会初始执行 默认初始执行一次(收集依赖)
依赖追踪 仅监听指定的数据源,若数据源是对象,需配置 deep: true 才会深度监听 自动追踪函数内所有响应式数据,包括对象深层属性
回调参数 回调函数接收新值、旧值两个参数((newVal, oldVal) => {} 回调函数无参数,仅执行副作用逻辑
停止监听 Vue 2 中通过 vm.$watch 返回的函数停止;Vue 3 中通过 watch 返回的函数停止 通过返回的函数停止监听

3. 用法示例

(1)watch 的用法(Vue 2 和 Vue 3 类似)

Vue 2 中:

js 复制代码
export default {
  data() {
    return {
      count: 0,
      user: { name: "张三" },
    };
  },
  watch: {
    // 监听基本类型
    count(newVal, oldVal) {
      console.log(`count 从 ${oldVal} 变为 ${newVal}`);
    },
    // 监听对象属性(需用字符串路径)
    "user.name"(newVal, oldVal) {
      console.log(`用户名从 ${oldVal} 变为 ${newVal}`);
    },
    // 深度监听对象(监听所有属性变化)
    user: {
      handler(newVal) {
        console.log("user 对象发生变化", newVal);
      },
      deep: true, // 开启深度监听
      immediate: true, // 初始化时执行一次
    },
  },
};

Vue 3 组合式 API 中:

js 复制代码
import { ref, reactive, watch } from "vue";

export default {
  setup() {
    const count = ref(0);
    const user = reactive({ name: "张三" });

    // 监听 ref
    watch(count, (newVal, oldVal) => {
      console.log(`count 从 ${oldVal} 变为 ${newVal}`);
    });

    // 监听 reactive 对象的属性
    watch(
      () => user.name,
      (newVal, oldVal) => {
        console.log(`用户名从 ${oldVal} 变为 ${newVal}`);
      }
    );

    // 深度监听(Vue 3 中监听 reactive 对象默认深度监听)
    watch(
      user,
      (newVal) => {
        console.log("user 对象变化", newVal);
      },
      { immediate: true }
    );
  },
};
(2)watchEffect 的用法(仅 Vue 3)
js 复制代码
import { ref, reactive, watchEffect } from "vue";

export default {
  setup() {
    const count = ref(0);
    const user = reactive({ name: "张三", age: 20 });

    // 自动追踪函数内使用的响应式数据
    const stop = watchEffect(() => {
      // 用到了 count 和 user.name,这两个数据变化时会触发回调
      console.log(`count: ${count.value}, 用户名: ${user.name}`);
    });

    // 3秒后停止监听
    setTimeout(stop, 3000);
  },
};
  • 初始时会执行一次,打印初始值。
  • countuser.name 变化时,会重新执行回调。
  • user.age 变化时不会触发,因为函数内未使用该属性(自动追踪依赖)。

4. 适用场景

  • watch

    适合需要明确知道数据变化前后的值只监听特定数据源需要控制是否深度监听/初始执行的场景。例如:监听路由变化、根据旧值和新值做不同处理。

  • watchEffect

    适合依赖较多且不需要区分新旧值的场景,写法更简洁。例如:数据变化后同步更新 DOM、发送请求等副作用操作。

总结

  • watch 更灵活,需手动指定监听源,可获取新旧值,适合精确控制的场景。
  • watchEffect 更简洁,自动追踪依赖,默认初始执行,适合副作用逻辑较简单的场景。
  • 注意:watchEffect 是 Vue 3 新增 API,Vue 2 中无法使用。