vue3子组件改造props的值

1,514 阅读3分钟

vue3工作场景,父组件传值给子组件,子组件需要对父组件传过来的值进行跟更改,但是会发现props里面的值是被proxy包裹的而且数据是嵌套proxy,根本解构不了不管是使用toRaw()还是JSON.parse(JSON.stringify())都无法解构里面的引用型(数组)

image.png props的套娃结构 在 vue3 里面,reactive、shallowReactive、readonly、shallowReadonly 都用了proxy,那么到底是哪一种呢?

简单测试一下就会发现是 shallowReadonly(浅层只读),那么问题来了,既然不让改,为啥不用 readonly?是遗漏了吗?

我猜测这是一个平衡各种需求后的折中处理方案。

然后可能官方为了避免心智负担,于是干脆一刀切,就说不让改props,这样就省事了。

而对于懂得原理的,那就可以传递引用类型,实现更简洁的操作方式。

所以想要用好一个框架,还是需要了解一些原理的。分清楚什么情况可以改,什么情况不可以改,可以让代码更简洁。

为啥不可以改 props,为啥又可以改props?

现在来讨论一下,props 到底可不可以改的问题。

按照官网的说法,子组件是不可以修改 props 的,原因云云,于是好多人也跟着说不能改,改了就云云。

那么本质原因是啥呢?知其然还要知其所以然!

61.png

props不同的类型

这个要从js的数据类型说起,js的类型比较乱,有很多种划分方式,从传递的角度来看,可以分为传值类型和引用类型。

  • 传值类型:拷贝副本传递,改副本不影响原值!
  • 引用类型:传递地址,可以通过地址修改属性!

对于传值类型,传递副本之后,副本和“本尊”已经没有任何联系了,副本随便改,都不会影响“本尊”。

引用类型,传递的是自己的地址(指针),所以可以通过地址修改“本尊”的属性,这样改副本就可以影响到“本尊”。

vue组件的 props 能改与不能改,就是这两种传递方式导致的。

props 的本质形态

我们经常用到组件的 props,那么 props 到底是什么样子的呢?

这里以 Vue3 为例来分析一下,我们设置一个简单的父子组件,设置几种常见的类型:

  • 子组件
exportdefault defineComponent({
name: 'test2',
props: {
modelValue: String,
name: String,
user: Object,
info: Object
},
emits: ['update:modelValue'],
setup (props, context) {
console.log('props-text', props)
console.log('props-ctx', context)

// 使用 emit 修改
const submit = () => {
context.emit('update:modelValue', newDate())
}

// 使用 proxy 修改
const user = props.user // 可以直接获取,不需要使用 toRef
const direct = () => {
user.name = newDate()
}

return {
submit,
direct
}
}
})

子组件定义一个 props,有基础类型,和引用类型几个成员。基础类型需要使用 emit 来修改,引用类型(reactive),可以直接通过 proxy 的拦截原理来方向修改。

另外 props 的引用类型,是可以直接解构的,不需要使用 toRefs。

  • 父组件

模板:

<test
v-model="model"
:name="refName"
:user="retUser"
:attrs1="retUser"
>test>

js:

const model = ref('aa')
const refName = ref(0)
const retUser = reactive({
name: 'jyk'
})