Vue3 CompositionAPI为何使用toRef处理props?修改其值是否合理?
1. 已具备响应性的props为什么需要用toRefs处理?
props本身确实是Vue封装后的响应式对象,但直接解构props的基础类型属性会丢失响应性。
Vue的响应式基于Proxy实现,当你直接从响应式对象上解构基础类型属性(比如示例中的String类型user)时,拿到的只是值的拷贝,会和原props对象断开响应式关联,后续父组件修改user的值时,子组件中解构得到的变量不会同步更新,视图也不会触发响应式更新。toRefs(props)的作用是将props的每一个属性都转为指向原props属性的Ref对象,此时解构得到的user是Ref类型,本质保留了对原props.user的引用,父组件更新时user.value会同步变更,响应性不会丢失。即使是可选的对象类型属性,toRefs也会生成合法的Ref对象,避免属性未传时解构报错的问题。
反例(不使用toRefs的错误写法):
setup(props) { // 直接解构基础类型属性,丢失响应性 const { user } = props // 后续父组件更新user时,这里的user不会同步变化 }
2. 将props属性转成Ref是否允许直接修改?
绝对不可以直接修改props对应的Ref值,这违反了Vue的单向数据流设计原则。
toRefs的作用仅为保留解构后的响应性,没有任何“允许修改props”的含义。即使你修改转成Ref后的user.value,Vue也会在控制台抛出禁止修改props的警告,且只要父组件触发更新,你在子组件中本地修改的值会被父组件传下的props值直接覆盖,会出现数据不一致的问题,也会导致整个项目的数据流混乱,后期维护成本极高。
如果确实需要修改props对应的值,仍然要遵循单向数据流规范:子组件通过emit向父组件发送事件,由父组件修改源数据后再同步给子组件。如果需要在子组件内部临时维护可修改的状态,可以声明一个本地Ref,初始值取props的属性值即可:
const { user } = toRefs(props) // 本地可修改的独立状态,和props解耦 const localUser = ref(user.value) // 需要同步给父组件时,再emit事件通知父组件修改
内容的提问来源于stack exchange,提问作者kevinluo201

