Vue 3 中 Watch、WatchEffect 和 Computed 有什么本质区别?实战中怎么选?

在 Vue 3 的响应式系统中,Watch、WatchEffect 和 Computed 是开发者最常用的三个 API。它们都能监听数据变化,但各自的设计理念和适用场景却大不相同:
Computed 专注派生数据的缓存计算
Watch 提供精准控制的副作用监听
WatchEffect 实现自动追踪依赖的即时响应

理解三者的核心差异,将直接影响代码性能与可维护性。本文将通过原理对比和实战案例,帮你快速掌握选择技巧。

一、核心特性解析

1. Computed:缓存优化的计算属性
核心特点:
通过 `getter` 函数返回计算结果
自动缓存计算结果,依赖未变化时直接读取缓存
支持 `setter` 实现双向绑定(Vue 3.3+ 新增语法糖 `defineModel`)

典型场景:
```javascript
// 格式化商品价格显示
const formattedPrice = computed(() => `¥${(price.value discount.value).toFixed(2)}`);
```

2. Watch:精准控制的监听器
核心特点:
显式声明监听的数据源
可获取新旧值对比
支持深层监听(`deep: true`)和延迟执行(`immediate: false`)

典型场景:
```javascript
// 监听搜索关键词变化后发起请求
watch(searchKeyword, async (newVal, oldVal) => {
const results = await fetchResults(newVal);
searchResults.value = results;
}, { immediate: true });
```

3. WatchEffect:自动依赖追踪的副作用
核心特点:
自动收集回调函数内的响应式依赖
立即执行并响应所有依赖变化
支持异步副作用清理

典型场景:
```javascript
// 实时验证表单字段
watchEffect(async (onCleanup) => {
const timer = setTimeout(() => {
isValid.value = validateForm(field.value);
}, 500);
onCleanup(() => clearTimeout(timer));
});
```

二、核心差异对比

| 特性 | Computed | Watch | WatchEffect |
||-|-|-|
| 返回值 | 计算结果值 | 无 | 无 |
| 执行时机 | 依赖变化时 | 监听值变化时 | 依赖变化时 + 立即执行 |
| 依赖收集 | 自动 | 手动指定 | 自动 |
| 性能优化 | 缓存机制 | 精准控制依赖 | 可能重复触发 |
| 异步支持 | 不支持 | 支持 | 支持 |

三、实战选择策略

1. 优先使用 Computed 的场景
需要派生数据(如过滤列表、格式转换)
计算成本较高需要缓存优化
双向数据绑定(配合 `v-model` 使用)

2. 选择 Watch 的场景
需要新旧值对比(如撤销操作记录)
精确控制监听范围(避免无关数据触发)
异步操作(如 API 请求、定时任务)

3. 选择 WatchEffect 的场景
依赖关系复杂(自动追踪省去手动维护)
即时响应需求(如实时输入验证)
组合多个依赖(一处变化触发统一处理)

四、性能优化技巧

1. 避免 Computed 的滥用
副作用禁忌:不要在 computed 中修改外部状态
```javascript
// 错误用法 ❌
const badComputed = computed(() => {
localStorage.setItem('cache', data.value); // 产生副作用
});
```

2. 控制 Watch 的监听深度
精确控制:默认不启用 `deep: true`
```javascript
// 监听对象特定属性 ✅
watch(() => userInfo.value.name, (newName) => {...});
```

3. 优化 WatchEffect 的执行
手动清理:防止内存泄漏
```javascript
watchEffect((onCleanup) => {
const socket = connectSocket();
onCleanup(() => socket.close()); // 断开连接
});
```

五、常见问题解答

1. 如何选择 watch 和 watchEffect?
需要明确依赖项 → 选 watch
依赖项动态变化 → 选 watchEffect

2. Computed 能替代 watch 吗?
不能:computed 用于数据转换,watch 用于副作用操作

3. 三者可以组合使用吗?
可以:例如用 computed 处理数据,再用 watch 监听计算结果
```javascript
const filteredList = computed(() => list.value.filter(...));
watch(filteredList, (newList) => renderChart(newList));
```

结语
掌握 Computed、Watch 和 WatchEffect 的差异本质,关键在于理解其设计定位:
Computed 是数据加工流水线
Watch 是精准控制的触发器
WatchEffect 是智能响应的雷达

根据业务场景合理选择工具,既能提升代码性能,又能降低维护成本。建议收藏本文作为速查手册,遇到具体问题时对照决策流程图快速定位解决方案。