如何避免重新渲染由 v-for 指令创建的所有子组件
Posted
技术标签:
【中文标题】如何避免重新渲染由 v-for 指令创建的所有子组件【英文标题】:How to avoid rerendering all child components which are created by v-for directive 【发布时间】:2021-06-02 22:50:09 【问题描述】:有一个子组件列表
<question-list-item
v-for="(item, index) in questionListParsed"
:key="item.id"
:both-question="item"
:class-id="classId"
:subject-id="subjectId"
:index="index+1"
/>
questionListParsed 是 vuex 中的 getter。
/**************************************************************************
* getters
**************************************************************************/
get questionListParsed(): QuestionListItemRes[]
const questionList, showingOriginalQuestion = this
const questionListParsed = questionList.map((e) =>
const recommendQuestion = e.recommendedQuestions[0]
const recommendQuestionIds = showingOriginalQuestion[e.questionNumber]
let arr = []
if (recommendQuestionIds)
arr = recommendQuestionIds.filter((item) =>
return !this.removedRecommendQuestionIds.includes(item)
)
return
recommendQuestion:
...recommendQuestion,
stem: recommendQuestion.question,
knowledges: splitMultiKnowledge(recommendQuestion.knowledge),
questionSourceList: recommendQuestion.sources,
categoryId: recommendQuestion.categoryId,
,
originalQuestion:
...e,
id: e.questionNumber,
stem: e.question,
difficulty: e.complexity,
knowledges: splitMultiKnowledge(e.knowledge),
,
id: recommendQuestion.id,
questionSimilarId: e.questionNumber,
mistakeAnswerId: e.id,
targetExerciseId: e.targetExerciseId,
status: recommendQuestion.status,
)
return questionListParsed
questionListParsed 主要取决于状态 questionList 是来自服务器端的原始数据。现在我通过以下方式更改 questionList
@Mutation
updateQuestionListByIndex(data: UpdateParams): void
if (data.value)
const temp = [...this.questionList]
temp[data.index] = data.value
this.questionList = temp
并在这样的操作中提交突变
this.context.commit('updateQuestionListByIndex',
index: targetIndex,
value: originQuestion[0],
)
我只想更改数组 questionList 中的一项,然后 questionListParsed 更改。 预期是只更新了一个组件,但所有子组件都更新了(在其更新的飞节中使用 console.log('updated'))。
怎么做?
【问题讨论】:
【参考方案1】:您不需要阻止子组件重新渲染,Vue 会为您做到这一点。通过为每个列表元素 :key="item.id"
提供唯一键,您可以向 Vue 提供有关该项目的提示,因此 Vue 可以识别和重用已渲染的部分。
更多信息请参见https://vuejs.org/v2/api/#key。
【讨论】:
【参考方案2】:之所以更新所有组件,是因为你使用了计算属性(Vuex getter 是 Vue 计算属性)。
每当questionList
中的任何内容发生更改时,questionListParsed
都会重新计算,并且因为您正在使用 map
并生成新对象,结果是一个包含全新对象的新数组 --> 列表中的每个子项都会更新
我不会认为这是一个问题,因为实际上只有更改项目的 DOM 元素会被更新(这就是虚拟 DOM 的美妙之处)。如果您确实发现了一些性能问题,解决方法是停止使用computed
/getters,而是只在加载数据时进行一次转换,并继续仅使用questionListParsed
【讨论】:
关于虚拟 DOM,我完全同意你的看法。但是我需要点击一个按钮来调用服务器的api来更新questionList。所以我原本打算用getter。如果我只使用 questionListParsed 该怎么办 您真的发现您的应用程序有任何性能问题吗?有些操作很慢或类似的东西?以上是关于如何避免重新渲染由 v-for 指令创建的所有子组件的主要内容,如果未能解决你的问题,请参考以下文章
Vue中使用v-for渲染数据为何要添加key属性?(原理及作用)