Vue3 父组件异步数据传给子组件,视图未更新

由于项目组接入了一个新项目,用了 vue3 进行开发,遇到了这个问题,也是当时没想到原因吧,后来才恍然大悟,然后我们围绕着这个问题探究下。

问题描述

父组件传递给子组件一个引用对象的值,然后内部字段依赖后端接口,给到子组件进行下拉框数据展示,子组件数据未显示。下面我们用简单的代码回显下当时的问题。

子组件要拿到 columns 后需要做一些参数的处理

codeimg-twitter-instream-image (3).jpeg

codeimg-twitter-instream-image (4).jpeg

上面的代码效果如下图:子组件下拉是没数据的

image.png

问题分析

  1. 传递给子组件的是 optionList.value,它的引用已经变了,所以子组件没拿到更新后的值,那好,我们传 optionList,代码修改如下:

    Untitled (4).jpeg

    Untitled (5).jpeg

    上面的代码效果如下图:子组件下拉数据正常显示

    image.png

    但是这种只能使用ref定义,因为子组件取值用的是 .value,所以这种办法不可行。

  2. 传递给子组件的是 optionList.value,它的引用已经变了,所以子组件没拿到更新后的值,那好,我们不改变它的引用,代码修改如下:

    Untitled.jpeg

    Untitled (1).jpeg

    上面的代码效果:子组件下拉数据正常显示

    image.png

    无论是通过 push 方式还是直接赋值 在父组件中都是响应式的,为什么在子组件就必须通过 push 的方式呢,也就是说,使用 ref 或者 reactive 的方式 都不能改它的引用,这种方式行得通,但是很麻烦。所以就有了下面这一种。

  3. 子组件在处理 columns 使,用了 三点运算符,重新赋值给了一个新对象,我们尝试着直接返回原始值试试,代码修改如下:

    parent.jpeg

    child.jpeg

    上面的代码效果显示也是正常的,我们在子组件 循环时用 v-for 取的是 .value,那如果传进来的是 reactive 的,并通过 push 的方式行不通了,不过我们可以做下兼容,先取 item.options.value,再取 item.options

  4. 基于上面的改动,我们想,使用 reactive 并不通过 push 的方式,有其他的办法吗,其实我们可以使用 toRefs 将内部的每一个值都转变成 ref 形式的,代码如下:

    parent (1).jpeg

    child (1).jpeg

    上面的代码效果:子组件下拉数据正常显示

结论

  1. 是我们写法的问题,不应该使用 三点运算符 来对父组件的值做修改,如果想,可以使用 toRefs 或者 toRef(想要解构的值是可选的,不一定有) 在 setup 里面对 props 进行解构。
  2. 传值是 ref 的正常传递,如果是 reactive 应该使用 toRefs 拆出来单独传。

结尾疑问

细心的同学可能会有一个疑问,如果对 reactive 进行解构,会丢失响应式,查看了一下官网,也是说明了这一点,但是没有给出解释为什么是这样的,下期我们分析下原因。

猜你喜欢

转载自juejin.im/post/7079338726467305479
今日推荐