【问题标题】:why vue child component automatically changing data in parent component?为什么 vue 子组件会自动更改父组件中的数据?
【发布时间】:2021-06-16 05:28:00
【问题描述】:

我正在尝试这样的事情:

父组件

     <template v-else>
        <b-card class="d-flex card-shadow">
          <b-list-group-item
            class="d-flex justify-content-between border-0 pl-0"
            v-for="(userExperience, index) in userExperiences"
            :key="index"
          >
              <template>
                <p class="mb-0 fs--1 font-weight-600">
                  {{ userExperience.designation }}
                </p>
              </template>
              <template v-slot:action-buttons>
                <div class="d-flex mt-1">
                  <b-button
                    variant="link"
                    class="p-0 my-0 ml-0 no-underline fs--1 mr-3 text-blue font-weight-600"
                    v-b-modal.edit-experience-modal
                    @click="selectedExperience = userExperience"
                    >Edit or add details</b-button
                  >
                </div>
              </template>
            </summary-container>
          </b-list-group-item>
        </b-card>
        <edit-user-experience :experience="selectedExperience" />
      </template>

<script>
export default {
  data(){
    userExperiences: [],  // some data 
 }
}
</script>

EditUserExperience.vue

<b-modal
      id="edit-experience-modal"
      title="Edit Experience"
      cancelTitle="Discard"
      okTitle="Save"
      button-size="sm"
      hide-header-close
      return-focus="false"
      @ok="handleEditExperience"
      @hide="resetFormData"
    >
      <create-or-edit-experience-form
        v-model="userExperience"
        :experience="experience"
        :handle-submit="handleEditExperience"
        :loading="loading"
      />
</b-modal>

问题是在更改creatEorEditExperience 中的值时,它会改变父组件中userExperience 中的数据。可视化问题:

当我尝试更改1 中的数据时,它会自动更改2 中的数据。

有什么意义?

【问题讨论】:

  • 这就是v-model 所做的:双向绑定。如果您有两个(或更多)孩子,并且您将它们全部连接到父母中的同一属性,则从一个孩子更改它也会改变其他孩子。要将它们分开,您必须将每个孩子连接到不同的父道具。在这种情况下,首选解决方案是将 parent 中的 prop 作为数组,保存所有子 props 的值。当改变一个孩子的值时,它只会更新父数组中的那个位置,而其余的保持不变。
  • 但在这里我没有直接更改父数组。我将数组中的元素处理为一个新变量,然后将该变量作为道具传递给子组件。但是,子组件如何改变数组? @tao
  • 您似乎还不清楚“双向绑定” 是什么意思。孩子没有得到父母财产的副本。它获取对父属性的引用。当您更改子属性时,您实际上是在更改父属性。当您更改父属性时,它会在使用它的任何地方发生变化。在您的情况下,它在每个子实例中都会发生变化,因为通过使用 v-model 您将它传递给每个子实例。不是它的副本。它。父属性“实例”,我们应该称之为。
  • 知道了。你能用一些演示代码回答这个问题吗?
  • 您发布的代码不足以创建 runnable minimal reproducible example。使用codesanbox.io或类似的创建一个,我会为你修改它。

标签: vue.js vuejs2 vue-component


【解决方案1】:

正如我所料,您遇到的问题不止一个。

花点时间将您的沙盒与我在下面链接的沙盒进行比较。此外,如果要求不高,请将您的保留在当前状态(如果您想进行进一步的更改,请分叉它)。比较你和我所做的可能对未来遇到类似问题的用户有用。

我尽可能地消除了臃肿。要完全理解它,请阅读Custom events(尤其是.sync 修饰符)。也可以通过computed setters

重要提示:在EditUserExperience.vue 中,您会注意到我将experience 传播到名为userExperience 的计算中。我这样做是为了打破反应。如果我将experience 直接传递给&lt;user-experience-fields&gt;,模态中所做的更改将实时显示在UserExperience.vue 中。
但我们不希望这样,因为它会使 CancelOK 按钮无用。我们只想在用户按下 OK 时应用更改,这就是我将输入对象传播到基元(有效地克隆它)的原因。

这里是:https://codesandbox.io/s/two-way-binding-forked-9ewdc

【讨论】:

  • 这对我帮助很大!那么,在UserExperience.vue 中,我不应该使用类似&lt;template v-if="enableEdit"&gt;&lt;edit-user-experience :experience.sync="selectedExperience" /&gt;&lt;/template&gt; 的东西来启用EditUserExperience 的条件渲染吗?因为如果用户单击编辑按钮,我只会将其触发到 DOM 中。它对性能有什么积极影响吗?
  • @Osman,不,你不需要它。 &lt;b-modal&gt; 在打开之前不会渲染其内容,因此它已经有条件渲染。在相同的逻辑上将其包装成v-if 就像将内容多次包装到相同的v-if 中一样。它会起作用,但这不是必需的。你让浏览器做更多的工作而没有任何好处,所以从理论上讲,这很糟糕。在实践中,两者之间的差异是微不足道的。要查看它是否正常工作,请查看控制台中的标记:ClosedOpen.
  • 这将是一个有趣的测试:在我们开始看到可测量的性能下降之前,您需要将某些内容包装到同一个 v-if 包装器中多少次。我相信它必须至少成千上万次,如果不是更多的话。你问的是一次和两次之间是否有区别。
  • 你能回答这个问题吗? stackoverflow.com/questions/67091419/…@tao
  • @OsmanRafi,我所知道的是您必须正确配置服务器(您无法从客户端修复它)。服务器需要允许来自您调用的域的请求。但我不知道具体怎么做(它是后端的东西),它在很大程度上取决于运行服务器的内容(特定于每种类型的服务器:apache、nginx、iis 等)。为了正确理解 CORS,我推荐this resource。每次遇到 CORS 问题时,它都能帮助我理解原理并解决我的问题。
【解决方案2】:

v-model 将输入字段绑定到您要求的数据。通过要求 create-or-edit-experience 绑定到 userExperience,您是在告诉它主动更改存储在该对象中的值。

您可以在子组件中使用不同的对象来存储临时数据,然后在handleEditExperience 中您可以更改userExperience 中的数据。

它目前的工作方式是v-model的预期行为

【讨论】:

  • 好吧,我应该删除v-model还是更改userExperience的变量名?
  • 您可以将 v-model 设置为不同于 userExperience...updatedUserExperience 的对象。然后将一个对象添加到 handleEditExperience 使用的 EditUserExperience.vue
  • &lt;create-or-edit-experience v-model="updatedUserExperience" :experience="experience" :handle-submit="handleEditExperience"/&gt; 这就是现在的样子。但仍然存在同样的问题
猜你喜欢
  • 2017-11-13
  • 2021-03-08
  • 2021-02-15
  • 2022-09-17
  • 2018-09-06
  • 2017-06-13
  • 1970-01-01
  • 2020-07-17
相关资源
最近更新 更多