Vue中如何控制组件重渲染粒度?
我正在使用一个组件来呈现一个动态表,该表具有许多".行.有时我添加新行,有时我修改现有行,但每当我这样做时,Vue 都会重新渲染整个表格,这需要相当长的时间,我想避免这种情况.
I'm using a component to render a dynamic table which has "many" rows. Sometimes I add new rows, sometimes I modify existing rows, but whenever I do any of that, Vue will re-render the entire table and that takes a considerable time, which I would like to avoid.
我正在使用键和其他东西来加速重新渲染过程,但我仍然觉得这个过程效率低下:Vue 至少会遍历每一行,检查它是否发生了变化.
I'm using keys and stuff to accelerate the re-rendering process, but I still feel the process is inefficient: Vue will at least run through each row, checking whether it has changed or not.
<tr v-for="row in rows" :key="row['id']">....</tr>
我知道每次受影响的行.
I know the rows affected each time.
我如何告诉 Vue 它只应该在重新渲染时打扰那些?
How can I tell Vue it should only bother with those when it re-renders?
我考虑过有两个列表:固定列表和变化列表,但我不知道如何执行 <tr v-for="item in two_lists>/>
这样 Vue 在重新渲染时实际上会忽略第一个列表.
I have considered to have two lists: the stationary one and the changing one, but I have no idea how I could do the <tr v-for="item in two_lists"/>
such that Vue would actually ignore the first list when re-rendering.
OTOH,我还发现 这个线程 在最后一个回复中 NovaMage 给出了很好的解释.如果我读对了,如果我制作行组件并将单个行数据传递给它们,我会更好吗?因为一开始我并没有出于性能原因精确地将它们制作成组件(实例化数千个组件对性能来说永远不会太好,对吧?)
OTOH, I also found this thread with an excellent explanation by NovaMage in the last reply. If I read that correctly, I would be better off if I made rows components and passed individual row data to them? Because initially I DIDN'T make them components precisely for performance reasons (instantiating thousands of components can't ever be too good for performance, right?)
不管怎样,再说一遍:我如何告诉 Vue 它应该只在重新渲染时处理更改的行?
Anyway, again: How can I tell Vue it should only bother with changed rows when it re-renders?
推荐答案
在 Vue 中渲染粒度始终是一个组件.组件的模板被编译成一个渲染函数.当需要重新渲染时,渲染函数作为一个整体执行.模板编译器可以做一些优化(比如提升静态内容),据我所知,Vue 3 在这个领域有一些显着的改进但是我认为 v 的优化-for
循环不是其中之一(即仅渲染循环中的某些项目并跳过其他项目)
Rendering granularity in Vue is always a component. Component's template is compiled into a render function. When re-render is needed, render function is executed as a whole unit. There are some optimizations the template compiler can do (like hoisting static content for example) and from what I know there are some significant improvements in Vue 3 in this field but I think the optimization of v-for
loops is not one of them (ie. rendering only for some items in the loop and skip others)
所以是的,创建一个 Row
组件可能是一种优化某些操作的渲染性能的解决方案,但会消耗一些内存和实例化组件所需的时间.从数组中添加/删除项目可能仍会导致表格组件重新渲染,但即使在这种情况下,未更改的 Row
组件也不会重新渲染(参见下面的演示)
So yes, creating a Row
component might be a solution to optimize rendering performance for some operations at the cost of some memory and time needed for instantiating the components. Adding/removing items from array will probably still result in table component re-render, but unchanged Row
components will not re-render even in this case (see demo below)
我不知道很多"是什么意思.确切的意思是,但假设当时只有一小部分呈现的行在屏幕上可见,您可以做的最佳优化(评论中提到的分页除外)是使用某种虚拟滚动".组件 - 例如 vue-virtual-scroller
I do not know what "many" exactly means, but assuming only fraction of the rendered rows is visible on the screen at the time, the best optimization you can do (except of pagination mentioned in comments) is using some kind of "virtual scroll" component - for example vue-virtual-scroller
Vue.component("row", {
props: ["data"],
data() {
return {};
},
template: `
<tr>
<td><button @click="$emit('update-row', data)">Update row</button></td>
<td>{{ new Date() }}</td>
<td>{{ data.id }}</td>
<td>{{ data.text }}</td>
</tr>
`
});
const initialCount = 2
const vm = new Vue({
el: '#app',
data() {
return {
count: initialCount,
rows: Array.from({
length: initialCount
}, (v, i) => ({
id: i,
text: `text - ${i}`
}))
}
},
methods: {
addRow() {
this.rows.push({
id: this.count,
text: `text - ${this.count} `
})
this.count++
},
updateRow(row) {
row.text = row.text + 'U'
}
},
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
Table rendered: {{ new Date() }}
<button @click="addRow">Add row</button>
<table>
<tr v-for="row in rows" is="row" :data="row" :key="row.id" @update-row="updateRow" />
</table>
</div>
相关文章