CodeWalk

Vue3 computed与watch原理及最佳实践

作者:小字辈 · 2026-05-30 12:55

解释Vue3中computed和watch/watchEffect的原理区别、依赖追踪方式,以及使用场景选择。computed的懒计算(lazy)特性是如何实现的?watch的deep和immediate选项如何工作?

回答

小字辈

computed原理与特性

const doubled = computed(() => count.value * 2);

懒计算(Lazy)

  1. 创建时不执行getter,只在首次读取.value时计算
  2. 缓存结果:依赖不变直接返回缓存值
  3. 脏检查(dirty flag):依赖变化时标记为脏,下次访问重新计算
class ComputedRefImpl {
  constructor(getter) {
    this._dirty = true;   // 初始脏
    this._getter = getter;
  }
  get value() {
    if (this._dirty) {
      this._value = this._getter(); // 执行计算
      this._dirty = false;
    }
    track(this, 'value');
    return this._value;
  }
  // 依赖变化时:this._dirty = true
}

computed使用场景

  • 依赖state派生新数据(过滤/排序/格式化)
  • 需要缓存的昂贵计算
  • 不能有副作用(不修改state、不发请求)

watch/watchEffect原理

watch:显式指定监听源,精确控制

watch(source, (newVal, oldVal) => {
  // 可获取旧值
}, { deep: true, immediate: true });

watchEffect:自动追踪内部所有响应式依赖

watchEffect(() => {
  console.log(count.value, name.value); // 自动追踪
});

deep原理:递归遍历响应式对象的所有属性,在深层get时收集watch作为依赖

immediate原理:创建watch时立即调用一次回调(此时oldVal为undefined)

选择指南

场景选择
派生数据,需缓存computed
异步操作(请求/定时器)watch
需要旧值对比watch
多个依赖,自动追踪watchEffect
DOM操作或非响应式副作用watchPostEffect

最佳实践:

  • computed不要修改响应式state
  • watchEffect用于日志、同步localStorage
  • watch使用{ immediate: true }替代手动调用一次
  • 及时通过watchEffect/watch返回的stop函数清理监听