为啥 Vue 更新所有组件,而不仅仅是 v-for 中更改的组件?

Posted

技术标签:

【中文标题】为啥 Vue 更新所有组件,而不仅仅是 v-for 中更改的组件?【英文标题】:Why is Vue updating the all components instead of just the changed component in a v-for?为什么 Vue 更新所有组件,而不仅仅是 v-for 中更改的组件? 【发布时间】:2019-08-03 03:06:27 【问题描述】:

我有一个 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"
  
);

【问题讨论】:

【参考方案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”并且因此所有组件都会更新。

【讨论】:

以上是关于为啥 Vue 更新所有组件,而不仅仅是 v-for 中更改的组件?的主要内容,如果未能解决你的问题,请参考以下文章

Vue JS V-For 组件反应性

Vue 不会使用动态组件从 Vuex 更新 v-for 中的项目

vue.js - v-for 中动态生成的组件没有正确更新绑定属性

为啥Vue会更新父级中的变量-未使用事件

为啥 vue3 不必要地重新渲染 v-for 中的节点?

Vue 组件引入子组件v-for