Reputation: 13436
I have the following sample grid in which I push some new values to the bound list.
Press anywhere in the grid to push a new value to the grid.
As you can see in the fiddle, the updated cell will have a green
color for 500 ms, and all the re-rendered elements will have yellow
color.
The question is how we should configure Vue
component so that it only re-render the changed element instead of them all?
If you look at the fiddle console output, you will see numbers like (13001, 26001, ...) and this equals to the number of all cells (1000 rows x 13 columns).
.yellow {
background-color: yellow;
}
.pushed {
background-color: lightgreen
}
<script src="https://unpkg.com/vue">
var globalCount = 0;
</script>
<head>
<title>Vue Render Performance</title>
</head>
<div id="demo">
<demo-grid :data="gridData" :columns="gridColumns"> </demo-grid>
</div>
<script type="text/x-template" id="grid-template">
<table @click="pushData()">
<thead>
<tr>
<th v-for="key in columns">
{{key}}
</th>
</tr>
</thead>
<tbody>
<tr v-for="(entry, i) in data">
<td v-for="(key, j) in columns" :id="'a'+i +'_'+j">
{{renderMe(entry[key], 'a'+i +'_'+j)}}
</td>
</tr>
</tbody>
</table>
</script>
<script>
const data = newData(1000);
var renderedCount = 0;
var startTime = performance.now();
Vue.component('demo-grid', {
props: {
data: Array,
columns: Array,
renderCount: Object,
},
template: '#grid-template',
methods: {
renderMe(el, id) {
const elm = document.getElementById(id);
if (elm) {
elm.className += " yellow";
}
if (!renderedCount) {
renderedCount = 0
} else {
renderedCount++;
}
return el;
},
pushData() {
debugger
var push = function() {
let cols = ["Col1", "Col2", "Col3", "Col4", "Col5", "Col6", "Col7", "Col8", "Col9", "Col10", "Col11", "Col12", "Col13"];
var t0 = performance.now();
for (let i = 0; i < 1; i++) {
let newVal = Math.random() * 10000,
row = Math.round(Math.random() * 1000),
cellIndex = Math.floor(Math.random() * cols.length);
cell = cols[cellIndex];
if (data[row])
data[row][cell] = newVal;
var el = document.querySelector('tbody tr:nth-child(' + row + ') td:nth-child(' +
cellIndex +
')');
if (el) {
el.className = 'pushed';
el.scrollIntoView();
var t = function() {
if (el) {
el.className = '';
}
clearTimeout(t);
};
setTimeout(t, 500);
}
console.log('pushed to cell [' + row + ',' + cellIndex + '] :' + newVal);
console.log('Rendered Count: ' + renderedCount)
renderedCount++;
};
var t1 = performance.now();
console.log(t1 - t0)
};
push();
}
}
});
// bootstrap the demo
var demo = new Vue({
el: '#demo',
data: {
searchQuery: '',
gridColumns: ["Col1", "Col2", "Col3", "Col4", "Col5", "Col6", "Col7", "Col8", "Col9", "Col10", "Col11", "Col12", "Col13"],
gridData: data
}
})
Vue.config.devtools = true;
function newData(count) {
const data = [];
for (let i = 0; i < count; i++) {
data.push({
Col1: "Record",
Col2: 818959475,
Col3: 467587749,
Col4: 438,
Col5: 439,
Col6: 440,
Col7: 2.1,
Col8: 436.2,
Col9: 2.4,
Col10: 5770,
Col11: 5771,
Col12: 5772,
Col13: 5773
});
}
return data;
}
</script>
Upvotes: 1
Views: 1492
Reputation: 82499
When you don't want to re-render and entire list of information, the typical way to handle it is to push the things that need to re-render into a component. Here is an updated version of your code that pushes the rows into a component and renders a fraction of what you were doing before.
Vue.component("demo-row", {
props:["entry", "columns", "rowIndex"],
template:`
<tr>
<td v-for="(key, j) in columns" :id="'a'+rowIndex +'_'+j">
{{renderMe(entry[key], 'a'+rowIndex +'_'+j)}}
</td>
</tr>
`,
methods:{
renderMe(el, id) {
const elm = document.getElementById(id);
if (elm) {
elm.className += " yellow";
}
if (!renderedCount) {
renderedCount = 0
} else {
renderedCount++;
}
return el;
},
}
})
Vue.component('demo-grid', {
props: {
items: Array,
columns: Array
},
template: '#grid-template',
methods: {
pushData() {
this.$parent.pushData(this.$parent.gridItems, this.$parent.gridColumns);
}
}
});
Note, I did not change anything else that you are doing that could probably be done more idiomatically in Vue, I just wanted to demonstrate that there is no need for everything to re-render.
Upvotes: 4