必须先用toRefs再解构,因为直接解构会得到普通值副本而脱离Proxy追踪;toRefs将每个属性转为ref建立引用通道,确保修改count.value能同步更新源对象并触发视图刷新。

直接解构 reactive 对象会切断响应式连接,因为 JavaScript 解构取的是当前值的副本,不再经过 Vue 的 Proxy 拦截。要保留响应性,必须用 toRefs 先把每个属性转成独立的 ref,再解构。
为什么必须先 toRefs 再解构
Vue 的响应式依赖 Proxy 对整个对象的访问追踪。reactive({ count: 0 }) 返回的是一个代理对象,state.count 是响应式读取;但 const { count } = state 这一步只是把数字 0 赋给 count 变量,它变成普通值,后续修改不会触发更新。
-
toRefs(state)返回一个普通对象,里面每个属性都是ref,指向原对象对应字段 - 解构出来的
count是Ref<number>,修改需用count.value++ - 在模板中写
{{ count }}时,Vue 自动解包,无需写.value
标准写法:三步不能颠倒
顺序错一步就失效:
- 用
reactive创建响应式源:const state = reactive({ count: 0, name: 'Alice' }) - 立即用
toRefs包裹:const stateRefs = toRefs(state) - 再解构:
const { count, name } = stateRefs - 最后暴露给模板:
return { count, name }
常见错误和规避方式
容易踩坑的地方:
立即学习“前端免费学习笔记(深入)”;
- 对
ref({})直接调用toRefs→ 报错或无效;应先取.value:toRefs(user.value) - 动态新增属性(如
state.newField = 'x')后才调用toRefs→ 新字段不会出现在解构结果里 - 混用多个
reactive对象又不分别toRefs→ 推荐分开处理:{ ...toRefs(user), ...toRefs(config) } - 把计算属性或函数也塞进
toRefs→ 不需要,它们本身不是响应式对象,直接返回即可
替代选择:toRef 适合什么场景
如果只关心对象里的某一个字段,或者字段名是动态的、可能不存在,toRef 更轻量:
-
const countRef = toRef(state, 'count')—— 即使state.count后续才被赋值,它也能响应 -
toRef不要求源对象一定响应式,toRefs必须传入reactive对象 - 处理
props(尤其是readonly的)时更安全,不会意外修改原始值


















