vue响应式系统默认浅层监听,深层监听需显式启用deep: true;适用于ref复杂对象/数组内部变化,但性能开销大,推荐精准监听路径、计算属性或watcheffect替代。

Vue 响应式系统默认只做浅层监听——即只响应顶层属性的赋值变化,对对象内部嵌套属性(如 user.profile.avatar)或数组元素的修改不会自动触发更新。深层监听不是“开箱即用”的功能,而是需要明确启用并合理约束的优化行为。
什么时候必须用 deep: true?
当监听源是 ref 包裹的复杂对象或数组,且你关心其内部任意属性的变化时,deep: true 是必需的:
-
ref({ name: 'Alice', settings: { theme: 'dark' } })—— 修改settings.theme不会触发 watch,除非加{ deep: true } -
ref([{ id: 1 }, { id: 2 }])—— 推入新项或修改某项字段,同样需要 deep 才能捕获 -
reactive()对象本身已默认深度响应,但 watch 它时仍需deep: true才能拿到完整新旧值(否则只返回代理对象引用)
更高效的做法:避开 deep,直击路径
深层监听本质是递归遍历整个结构,性能开销随嵌套深度和数据量线性增长。多数场景其实只需关注某个具体字段:
- 监听
() => user.value.profile.city,而不是整个userref - 监听
() => list.value[0]?.title,而非整个数组 - 用计算属性收口逻辑:
const hasUnsaved = computed(() => JSON.stringify(form) !== savedState),再浅监听该计算值
watchEffect:自动追踪,但不返回旧值
如果你不需要对比新旧状态,只是想“只要相关数据一变就执行”,watchEffect 更轻量:
- 它自动分析函数体内访问的所有响应式属性,包括深层字段
- 无需配置
deep,也无需写取值函数() => ...,代码更紧凑 - 缺点是拿不到旧值,也无法控制是否立即执行(
immediate默认为 true)
性能敏感场景的加固策略
在表单、实时协作、大数据列表等高频更新场景中,深层监听容易成为瓶颈:
- 给 watch 加防抖:
watch(user, debounce(saveToServer, 500), { deep: true }) - 用
onInvalidate清理未完成的异步请求,避免竞态 - 对只读配置类数据,用
Object.freeze或shallowRef避免无谓代理 - 拆分大对象:把
user拆成userInfo、userSettings、userStats等多个独立 ref,按需监听
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!










