【问题标题】:Why is Vue updating the all components instead of just the changed component in a v-for?为什么 Vue 更新所有组件,而不仅仅是 v-for 中更改的组件?
【发布时间】:2023-04-02 02:50:02
【问题描述】:

我有一个 v-for 列表,其中包含一个组件。在组件内部,我根据属性的值显示<div><input>。问题是当我更改属性值时,v-for 中的所有项目都会更新,而不仅仅是更改的组件。这不是小型应用程序的问题,但我注意到在处理较大的数据集时性能显着下降。

所以基本问题是:

当只更新一个组件时,如何避免渲染所有组件?

我把它全部放在JSFiddle here 中。请注意,当您单击按钮以显示 C 组件输入时,所有组件都会重新呈现(显示在控制台中),而不仅仅是 C 组件。

HTML

<div id="app">
<button @click="showinput = 'C'">
Show C input
</button>
<br>
<br>
<div v-for="item in list" :key="item.id">
  <list-item :item=item :showinput="showinput"></list-item>
  </div>
</div>

<template id="list-item">  <span>  <div v-if="showinput !== item.name">
{{item.name}}</div>
<input v-else
    type="text"
    v-model.lazy="item.name"  >
</span>
</template>

JS

Vue.component('list-item', {
  template: '#list-item',
  props: ['item', 'showinput'],
  data () {
  return   {

  }},
  beforeUpdate() {
    console.log("Updating " + this.item.name)
  }
});

// create a new Vue instance and mount it to our div element above with the id of app
var vm = new Vue({
  el: '#app',
  data: {
  list: [{name: "A", id: 1}, {name: "B", id: 2}, {name: "C", id: 3},],
      showinput: "X"
  }
});

【问题讨论】:

    标签: vue.js vue-component v-for vue-reactivity


    【解决方案1】:

    当您按下“显示 C”按钮时,您正在更新 showInput 变量。现在这个showInput 变量作为prop 发送到v-for 中的每个&lt;list-item /&gt;,通过这样做,您正在更新所有组件。

    【讨论】:

      【解决方案2】:

      您的所有组件都使用相同的变量 showinput,因此所有组件都已更新。最终只显示一个并不重要,vue 不知道这一点。实际上,您仍在渲染跨度,但它们只是空的。

      您应该做的是过滤数据并在您的 v-for 中使用过滤后的数组。

      computed: {
        filteredList: function () {
           return this.list.filter( item => item.name === this.showInput )
         }
       }
      

      然后在你的 v-for 中

      <div v-for=“item in filteredList” ...
      

      如果您想显示所有信息,但要更改显示方式,您可以将list-item 组件拆分为 2 个组件,一个用于标签,一个用于输入。然后使用:is 选择要使用的模板(甚至是v-if)。我创建了这个fiddle 来查看它的实际效果。请注意,onBeforeUpdate 将不再被调用,因为 vue 会重新创建组件。

      在 vue 3 中这似乎可以修复,因为它将支持组件的部分渲染。

      【讨论】:

      • 谢谢!我明白这个问题。但是,计算过滤器真的可行吗?这会过滤掉一些数据:我希望显示所有数据 - 只是以不同的形式。解决方案是否可以让一个子组件带有输入字段,一个没有,然后在父组件中执行 v-if 来决定显示哪个?
      • 您可以使用补充过滤器,它使用 !==,而不是 ===。但这是一个不同的问题,您可能应该就 SO 提出其他问题。
      • 谢谢,但我不关注这个。我想以相同的顺序显示所有数据 - 只有一些作为输入字段,一些作为跨度。那么我怎样才能使用计算过滤器呢?请您指出我应该搜索的正确方向吗?同时,我确实尝试了我自己的建议,使用两个不同的子组件和 v-if,虽然性能稍微好一点,但并没有太大的区别。
      • 感谢您的帮助!
      【解决方案3】:

      在您的组件“list-item”中,您有一个名为“showinput”的道具。 所以每次改变这个 prop 的值,你的组件都会更新。

      现在,每当您单击“显示 C 输入”时,您都会更新“showinput”,并且当您将“v-for”用于“list-item”组件时,每个“list-item”都会附加“showinput”并且因此所有组件都会更新。

      【讨论】:

        猜你喜欢
        • 2020-12-15
        • 1970-01-01
        • 2020-06-18
        • 2021-05-21
        • 2018-08-24
        • 2019-01-30
        • 1970-01-01
        • 1970-01-01
        • 2021-12-16
        相关资源
        最近更新 更多