直接解构 props 会丢失响应式,因解构获取的是值快照,脱离 proxy 代理;而 torefs 将各 prop 包装为 ref,重建响应式连接,使解构变量仍可追踪更新。

直接解构 props 会丢失响应式,是因为 JavaScript 解构赋值拿到的是那一刻的值快照,脱离了 Vue 的 Proxy 代理层,后续父组件更新无法触发子组件重新渲染。要让解构后的变量仍能响应变化,必须借助 toRefs 或 toRef 等工具重建响应式连接。
为什么 props.title 可以响应,而 const { title } = props 不行?
Vue 的响应式依赖“读取时收集依赖、写入时触发更新”。每次访问 props.title,Proxy 的 get 拦截器都会被调用,从而把当前副作用(如模板渲染)和该属性关联起来。但解构是一次性读取并赋值,之后所有操作都发生在普通变量上,Proxy 完全无感知。
-
props.title:持续走代理,可被追踪 -
const { title } = props:只读一次,后续与代理无关 - 即使
title是对象或数组,解构后也失去响应式层级穿透能力
toRefs 是怎么恢复响应式的?
toRefs 并不改变原始 props,而是把每个 prop 属性包装成一个独立的 ref。这些 ref 拥有自己的依赖收集系统,因此解构出来的变量仍是响应式引用。
-
toRefs(props)返回类似{ title: ref('xxx'), count: ref(0) } -
const { title } = toRefs(props)→title是 ref,不是字符串 - 在模板中写
{{ title }},Vue 会自动读取title.value并建立依赖 - 在 script 中使用需通过
title.value读写(setup()函数内)
三种实用解构方式对比
根据场景选择合适方案,避免一刀切:
-
批量解构全部 props:用
toRefs(props),适合 props 字段较多、逻辑集中处理的场景 -
只取个别字段:用
toRef(props, 'title'),更轻量,类型推导更精准 -
仅模板中使用、不需 JS 层操作:直接写
props.title,零额外开销,最简洁 - 需要派生计算(如格式化、过滤):优先用
computed(() => props.title.toUpperCase()),天然响应式且不可变
常见误区与注意事项
几个高频踩坑点,务必避开:
- 不能对
props.user.name直接调用toRefs,因为props.user本身可能不是 reactive 对象;应先确保它是响应式源,或改用computed封装 - 若用
ref({})包裹对象再传入 props,需先取.value再调用toRefs,即toRefs(props.obj.value) - 不要手动用
ref(props.title)“修复”解构结果——它包裹的是初始值,不会随props.title更新 - 配合
defineProps使用时,toRefs仍适用,且 TypeScript 类型推导更友好
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!










