由于项目组接入了一个新项目,用了 vue3
进行开发,遇到了这个问题,也是当时没想到原因吧,后来才恍然大悟,然后我们围绕着这个问题探究下。
问题描述
父组件传递给子组件一个引用对象的值,然后内部字段依赖后端接口,给到子组件进行下拉框数据展示,子组件数据未显示。下面我们用简单的代码回显下当时的问题。
子组件要拿到
columns
后需要做一些参数的处理
上面的代码效果如下图:子组件下拉是没数据的
问题分析
-
传递给子组件的是
optionList.value
,它的引用已经变了,所以子组件没拿到更新后的值,那好,我们传optionList
,代码修改如下:上面的代码效果如下图:子组件下拉数据正常显示
但是这种只能使用ref定义,因为子组件取值用的是
.value
,所以这种办法不可行。 -
传递给子组件的是
optionList.value
,它的引用已经变了,所以子组件没拿到更新后的值,那好,我们不改变它的引用,代码修改如下:上面的代码效果:子组件下拉数据正常显示
无论是通过
push
方式还是直接赋值 在父组件中都是响应式的,为什么在子组件就必须通过push
的方式呢,也就是说,使用ref
或者reactive
的方式 都不能改它的引用,这种方式行得通,但是很麻烦。所以就有了下面这一种。 -
子组件在处理
columns
使,用了三点运算符
,重新赋值给了一个新对象,我们尝试着直接返回原始值试试,代码修改如下:上面的代码效果显示也是正常的,我们在子组件 循环时用
v-for
取的是.value
,那如果传进来的是reactive
的,并通过push
的方式行不通了,不过我们可以做下兼容,先取item.options.value
,再取item.options
。 -
基于上面的改动,我们想,使用
reactive
并不通过push
的方式,有其他的办法吗,其实我们可以使用toRefs
将内部的每一个值都转变成ref
形式的,代码如下:上面的代码效果:子组件下拉数据正常显示
结论
- 是我们写法的问题,不应该使用
三点运算符
来对父组件的值做修改,如果想,可以使用toRefs
或者toRef
(想要解构的值是可选的,不一定有) 在setup
里面对props
进行解构。 - 传值是
ref
的正常传递,如果是reactive
应该使用toRefs
拆出来单独传。
结尾疑问
细心的同学可能会有一个疑问,如果对 reactive
进行解构,会丢失响应式,查看了一下官网,也是说明了这一点,但是没有给出解释为什么是这样的,下期我们分析下原因。