直接解构 reactive 对象会丢失响应性,因为取出来的是普通值;toRefs 和 toRef 不新建响应式,而是建立指向原属性的引用通道,使解构后变量仍能触发更新。

直接解构 reactive 对象会丢失响应性,因为取出来的是普通值,不再经过 Proxy 拦截;toRefs 和 toRef 的作用不是“新建响应式”,而是建立指向原属性的引用通道,让解构后的变量仍能触发更新。
toRefs:批量解构已知结构的 reactive 对象
toRefs 专为 reactive 对象设计,把它的每个第一层已有属性都转成独立的 ref,返回一个普通对象(非响应式),但其中每个字段都是可读写的 ref,因此支持安全解构。
- 必须传入
reactive或shallowReactive创建的对象,对普通对象或ref().value调用无效 - 解构后需通过
.value修改,如count.value++,模板中可省略.value - 不处理嵌套对象,若
state.user是 reactive,需额外对user再调一次toRefs或用toRef - 常见于组合式函数返回值,例如:
return { ...toRefs(user), ...toRefs(config), submit }
toRef:按需提取单个可能不存在的属性
toRef 不要求源对象是 reactive,也不检查属性是否存在。它只建立一个“引用链接”,即使属性当前为 undefined,也能安全创建 ref,并支持设置默认值。
- 适合从
props、API 响应数据、或动态字段对象中提取某一项,例如:toRef(props, 'title', '无标题') - 修改
xxxRef.value会同步更新源对象对应属性,源对象变化也会反映到xxxRef.value - 不能直接解构,因为它只返回一个
ref,不是对象;写法是const nameRef = toRef(obj, 'name') - 对
readonly的props安全,不会触发警告
为什么解构会断开响应式连接
Vue 的响应式依赖拦截机制:reactive 返回的是 Proxy 对象,所有响应行为都绑定在它身上;ref 则靠 .value 上的 getter/setter 触发追踪。一旦执行 const { count } = state,本质是 const count = state.count,拿到的就是脱离代理的原始值。
立即学习“前端免费学习笔记(深入)”;
- 这个
count是普通数字,赋值count = 5只改局部变量,不触发 set,也不通知依赖 -
toRefs把state.count包装成ref(0),后续count.value = 5就能走 ref 的 setter,完成响应式更新 - 两者都不复制数据,只是复用原有响应式追踪关系,性能更轻量
常见误用与避坑提示
这两个 API 看似简单,但错用会导致静默失效,尤其在组合式函数和跨组件传参时。
- 不要对
ref调用toRefs,ref本身已是响应式,正确做法是直接用.value或封装访问器 - 解构
toRefs结果后忘记加.value,比如写成name = '新名字'而非name.value = '新名字' - 把
toRef当成批量工具,写成toRef(obj, ['a', 'b'])—— 这会报错,批量只能用toRefs - 在 Options API 或非
setup脚本中使用时,模板绑定要写{{ count.value }},不能省略


















