uni-app中watch监听对象属性不触发需加deep: true,小程序端对响应式变化保守;推荐精准监听字段如watch(() => user.value.name, ...)或用splice等变异方法替代索引赋值。

uni-app 里 watch 监听对象属性不触发?先看 deep: true 加没加
小程序端(尤其是微信、支付宝)对响应式对象的内部变化监听非常保守,watch(user, () => {}) 默认只监听 user 引用是否被整体替换,比如 user = ref({ name: 'Tom' }) 这种赋值才会触发;而 user.value.name = 'Jerry' 完全静默——除非显式加 { deep: true }。
常见错误现象:
- 修改
list.value[0].done = true,watch 回调不执行 - 在
<input v-model="form.name">输入后,watch(form, ...)没反应 - Vue 2 选项式写法中写成
form: { handler() {}, deep: true }却漏了handler字段名,直接报错
setup 语法糖中监听对象字段:别直接 watch 整个 ref
watch 在 <script setup></script> 里是函数调用,不是配置对象。最常踩的坑是把「监听某个字段」写成「监听整个 ref」却不加 deep:
- ❌ 错误:
watch(user, () => {})——user.value.name改了也不触发 - ✅ 推荐(精准):
watch(() => user.value.name, (newVal) => {})—— 只响应 name 变化,无性能开销 - ✅ 可选(宽泛):
watch(user, () => {}, { deep: true })—— 但注意:只要user任意嵌套属性变就触发,大数据量时卡顿明显
监听数组内部字段也同理:watch(() => list.value.map(i => i.done), () => {}) 比盲目加 deep: true 更可控。
Vue 2 选项式写法中 deep 配置必须带 handler
Vue 2 的 watch 是对象形式,字段值不能直接写函数,否则 deep 和 immediate 会失效:
- ❌ 错误:
user: { deep: true, immediate: true }—— 缺少handler,不执行回调 - ✅ 正确:
user: { handler(newVal, oldVal) { /* 逻辑 */ }, deep: true, immediate: true } - ⚠️ 注意:
immediate: true不是默认行为,要手动加才在组件创建时立即执行一次
为什么数组索引赋值监听不到?因为小程序不代理原始操作
在小程序平台,arr[0] = { done: true } 这类直接索引赋值不会触发响应式更新,所以 watch 也收不到。这是底层 proxy 实现限制,不是你代码写错了。
- ✅ 替代方案一:用
arr.splice(0, 1, { done: true })—— 变异方法能触发 - ✅ 替代方案二:用
watch(arr, ..., { deep: true })—— 强制深度遍历,但慎用于长列表 - ✅ 替代方案三(推荐):监听关键字段数组,如
watch(() => arr.value.map(i => i.done), () => {})
真正容易被忽略的是:deep 监听在 H5 端可能“看起来正常”,但一到小程序就失效——不要依赖开发工具预览,务必真机测试。


















