为什么Vue3中监听ref对象指定属性时会响应全量属性变更?
问题根因
你的代码存在三个核心问题,导致监听范围超出预期:
toRef用法错误:note本身是Ref<Note>类型的ref对象,它的value属性才是你定义的Note类实例。你直接把note作为toRef的第一个参数,相当于尝试从{ value: 实例 }这个ref外层对象上获取title/text等不存在的属性,这会导致computed求值时直接依赖整个note.value,所有Note属性变更都会触发依赖更新。- 多余的
deep: true配置:就算你修正了toRef的写法,监听包含ref的数组时开启深度监听,Vue会递归遍历所有可访问的响应式属性,也会额外收集到不属于你指定四个属性的依赖,造成误触发。 - 无意义的computed包装:你用computed返回属性ref的数组,每次computed触发都会生成新的数组实例,引用变更本身也会触发watch回调。
修正方案
直接给watch传入属性ref的数组即可,不需要包computed,也不需要全局开启深度监听:
const props = defineProps({ currentNote: {type: Object as () => Note, default: () => {return {}}}, }) const note = toRef(props, 'currentNote') as Ref<Note> // 直接从note.value上获取属性ref const toWatch = [ toRef(note.value, 'title'), toRef(note.value, 'text'), toRef(note.value, 'tags'), toRef(note.value, 'type') ] // 直接监听ref数组,不需要deep配置 watch(toWatch, debounce(() => { console.log(JSON.stringify(note)) note.value.writeToOffline() }, 1000))
如果需要兼容note.value可能为空的场景,可以用函数返回监听值的写法,此时只需要为数组类型的tags单独开深度监听即可,不会影响其他属性:
watch( () => [note.value?.title, note.value?.text, note.value?.tags, note.value?.type], debounce(() => { console.log(JSON.stringify(note)) note.value?.writeToOffline() }, 1000), { deep: true } )
内容的提问来源于stack exchange,提问作者WoJ
相关产品推荐
相关产品推荐

