跳转至

子组件修改数据影响父组件问题

当您在子组件中修改通过 props 传递的对象时,实际上您是在修改这个对象的引用,而这个引用同时也被父组件持有。在 JavaScript 中,对象是通过引用传递的,这意味着当您传递一个对象给一个函数或组件时,您实际上传递的是这个对象的引用。所以,当您在子组件中修改这个对象时,父组件中的相应对象也会发生变化,因为它们指向的是同一个内存地址。

为了避免这种情况,您可以在子组件中创建传递对象的深拷贝。这样,当您修改子组件中的对象时,不会影响父组件中的对象。深拷贝意味着创建一个新对象,并递归复制原始对象的所有属性到新对象中。

showModal 方法中,您可以使用深拷贝来创建 analysisForm 的副本,例如使用 JSON 的 parsestringify 方法:

showModal(item, parsingFilesList) {
  this.visible = true;
  // 创建 item 的深拷贝
  const analysisInit = JSON.parse(JSON.stringify(item));

  // ...省略的代码...

  // 现在 this.analysisForm 是一个深拷贝
  this.analysisForm = analysisInit;
  this.parsingFilesList = parsingFilesList;

  // ...省略的代码...
}

请注意,使用 JSON 的 parsestringify 方法进行深拷贝有一些局限性,比如它不能复制函数和 Symbol 类型的值。如果对象结构更复杂或包含特殊类型(例如函数、日期、RegExp 等),您可能需要一个更强大的深拷贝实现,例如使用 Lodash 库的 _.cloneDeep 方法。

如果 analysisForm 中的数据结构并不复杂,使用 JSON 方法进行深拷贝通常是足够的。但如果有特殊情况,您应该选择更适合的深拷贝方法。

我没通过props传递,我是通过this.$refs.CalculationDesignAnalysisModal.showModal(record, this.calculateForm.calculateInfo);这种 $refs 传递的

即使您没有通过 props 直接传递数据,但通过 $refs 调用子组件的方法并传递对象时,也是通过引用传递的。这意味着子组件和父组件中的 record 对象是同一个对象。因此,当您在子组件中修改这个对象时,实际上也修改了父组件中的对象。

为了防止这种情况,您应当在子组件中对传入的对象进行深拷贝,这样您就可以在子组件中操作这个对象的副本,而不会影响到父组件中的原始数据。以下是修改后的 showModal 方法,其中使用了 JSON.parse(JSON.stringify()) 来创建 record 的深拷贝:

showModal(item, parsingFilesList) {
  this.visible = true;
  // 使用 JSON.parse(JSON.stringify(item)) 创建 item 的深拷贝
  const analysisInit = JSON.parse(JSON.stringify(item));

  // 其余的初始化代码
  // ...

  // 使用深拷贝的数据初始化 analysisForm
  this.analysisForm = analysisInit;
  this.parsingFilesList = parsingFilesList;

  // 其余的初始化代码
  // ...
}

现在,即使您在子组件中更改了 analysisForm,它也不会影响到父组件中的 record 对象。

请注意,使用 JSON.parse(JSON.stringify()) 进行深拷贝有局限性,它不能复制函数、undefined、循环引用等。如果您的对象中包含这些类型的数据,您可能需要使用更复杂的深拷贝方法,例如使用 lodash 的 cloneDeep 函数。

在 Vue 中,通常建议避免直接修改父组件的状态,而是应该使用事件(通过 $emit)将需要的更改发送回父组件,并让父组件负责更新状态。这样可以保持组件间的数据流向清晰,并有助于维护和调试。