今天遇到个偶现的bug:父组件传递了一个对象给子组件,子组件中使用这个对象中的部分元素变为undefined。

问题分析:

父组件的这个对象(task)是通过computed侦听http接口返回的数据后被赋值的(这个http接口5s被调用一次),子组件中变为undefined的元素(stageEnv)是在父组件mounted方法中动态赋值的(此前这个对象中未定义此元素):

mounted() {
    ...
    if (this.story.stages[this.index]['stageEnv']) {
      this.task.stageEnv= this.story.stages[this.index]['stageEnv']
    } else {
      this.task.stageEnv= ''
    }
    ...
    this.taskInfo = this.task // 把task赋值给taskInfo
    ...

}

taskInfo是最终传递给子组件的对象。

在代码中加了各种log和断点后终于发现问题就出现在了this.taskInfo = this.task这里,在mounted执行结束前,有http接口调用返回导致task被更新,这里taskInfo的赋值使用的是浅拷贝,意味着taskInfo也被刷新了,给它赋的stageEnv也没有了,而它依旧会被继续传递给子组件,就出现了我遇到的问题。

解决方案:

在mounted开始时就使用深拷贝将task的值赋值给task,后续的赋值也直接赋给taskInfo,这样即使task发生了变更,也不影响传递进子组件的数据(但是这里需要注意的是,如果父组件其他地方也使用了mounted中赋值的这个元素,其他地方也需要将this.task.xxx改为this.taskInfo.xxx):

mounted() {
    for (const key in this.task) {
      this.taskInfo[key] = this.task[key]
    }
    ...
    if (this.story.stages[this.index]['stageEnv']) {
      this.taskInfo.stageEnv= this.story.stages[this.index]['stageEnv']
    } else {
      this.taskInfo.stageEnv= ''
    }
    ...

}

总结:

在使用子组件的场景中,如果传递给子组件的对象来自计算属性,且此计算属性监听的数据来自不断定时更新的数据,且传递给子组件前会对此对象的值进行变更,则需要在mounted开始时就使用深拷贝将此对象值拷贝出来,防止在加载子组件的半路上计算属性更新引起值丢失的问题。这几种因素组合在一起简直太巧了~记录一下

Logo

前往低代码交流专区

更多推荐