解构 reactive 对象会丢失响应式,因其脱离 Proxy 监控;应使用 toRefs 保持追踪,或避免解构、改用 props.xxx/computed 访问。

直接解构 reactive 对象会让响应式“消失”,不是数据没变,而是 Vue 再也收不到变化通知了。根本原因在于:解构拿到的只是那一刻的值或普通引用,脱离了 Proxy 代理的监控范围。
为什么解构会切断响应式
reactive 返回的是一个 Proxy 代理对象,它的响应式能力只作用于对这个代理对象的访问路径(比如 state.count)。一旦你写 const { count } = state,JavaScript 就执行一次取值 + 赋值:
- 对基本类型(如 number、string),得到的是值拷贝,完全独立于原始响应式系统
- 对嵌套对象(如 state.user),得到的是原始对象的内存引用,不是它的代理,后续修改 user.name 不会触发 set 拦截
- 所有这些变量都不经过 track/trigger 机制,Vue 渲染函数压根不知道它们变了
安全解构的正确姿势
想解构又不丢响应式,关键是要让每个字段仍能被 Vue 追踪。推荐用 toRefs:
- const { count, user } = toRefs(state) —— 每个解构出来的变量都是 ref,内部包裹着响应式链接
- 模板中可直接写 {{ count }}(Vue 自动解包)
- 逻辑中读写需加 .value:count.value++ 或 user.value.name = '李四'
- 如果只是临时读取、不打算修改,就别解构,直接用 props.count 或 state.user.name
替代方案:避免解构,改用 computed 或 props 访问
不是所有场景都需要解构。很多时候更简洁、更安全的做法是绕过它:
- 在模板里直接写 {{ props.count }} 或 {{ state.user.name }}
- 需要派生计算时,用 computed(() => state.count * 2),依赖自动追踪
- 子组件接收 props 后,不要写 const { title } = props,而是始终通过 props.title 使用
- 工具函数需要处理响应式字段时,传整个 reactive 对象或具体 ref,而不是解构后的值
特别注意父子组件间的数据流转
父组件用 reactive 定义数据,传给子组件后失效,往往不只是解构问题:
- 父组件别写 state = { ... } 替换整个对象,这会扔掉代理;应改属性:state.count = 100 或 Object.assign(state, newData)
- 子组件 setup 中若用 defineProps,也要避免对 props 解构,或必须配合 toRefs(props)
- 如果 props 是 shallowRef 包裹的对象,内部属性修改不会响应,此时要么换 ref,要么手动 triggerRef


















