在 Vue 3 中,从响应式对象(reactive)身上直接解构出来的数据会失去响应性,这其实是因为 JavaScript 的解构赋值机制与 Vue 3 的响应式原理(Proxy)产生了冲突。
简单来说,解构操作直接“剥离”了 Vue 施加在对象上的魔法外壳。
🔍 为什么会失效?
Vue 3 的 reactive 是通过 Proxy(代理) 来实现响应式的。当你访问 state.xxx 时,Proxy 会拦截这个操作,帮你收集依赖(知道谁在用这个数据);当你修改它时,Proxy 会再次拦截并触发视图更新。
但是,当你使用解构赋值时:
const state = reactive({ count: 0 })
const { count } = state
这行代码在 JavaScript 底层等价于:
const count = state.count
这一步操作,相当于直接把 state 对象里 count 的原始值(比如数字 0)拷贝了出来,赋值给了一个全新的普通变量 count。这个新变量 count 只是一个普通的 JavaScript 值,它脱离了 state 的 Proxy 代理控制。所以,后续你修改 count,Vue 根本感知不到,视图自然也就不会更新。
✅ 如何解决?(使用 toRefs)
如果你非常想在模板或逻辑中直接解构使用,Vue 提供了 toRefs 这个 API 来完美解决。它的作用是把响应式对象里的每一个属性,都转换成一个独立的 ref 响应式引用。
import { reactive, toRefs } from 'vue'
const state = reactive({ count: 0, name: 'Vue' })
// 使用 toRefs 包裹后再解构
const { count, name } = toRefs(state)
// 此时 count 和 name 都是 ref 对象,保持响应式!
// 在 JS 中修改需要通过 .value
count.value++
在 Vue 的 <template> 模板中,ref 会自动解包,所以你依然可以直接写 {{ count }},不需要写 .value。
💡 补充两个小技巧
1. 只解构单个属性用 toRef:如果你只需要解构某一个属性,可以使用 toRef(state, 'count'),效果和 toRefs 一样,但更轻量。
2. Vue 3.5 的新特性:如果你使用的 Vue 版本在 3.5 及以上,官方对 defineProps 做了优化。现在直接从 defineProps 里解构出来的 props 是默认保持响应式的,不再需要手动包 toRefs 了。

988

被折叠的 条评论
为什么被折叠?



