Why Not Use :key="index" in Vue v-for? Understanding Virtual DOM and Diff Algorithm
This article explains why using :key="index" in Vue v-for loops is problematic, describes the virtual DOM compilation process, demonstrates the diff algorithm with examples, and provides best practices for key usage to improve rendering performance.
When using v-for in Vue, many developers mistakenly write :key = "index" . This article argues that such usage should be avoided and explains the reasons behind it.
Vue first compiles the template into a virtual DOM, which is an in‑memory representation of the UI. The virtual DOM is then transformed into real HTML that the browser renders.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
</head>
<body>
<div id="app">
<ul id="item">
<li v-for="item in list" class="item">{{item}}</li>
</ul>
</div>
<script>
const { createApp, ref } = Vue
createApp({
setup() {
const list = ref(['vue','js','html'])
return { list }
}
}).mount('#app')
</script>
</body>
</html>The template above actually renders three <li> elements. Vue's compiler turns this template into a virtual DOM structure like the following:
let oldDom = {
tagName: 'ul',
props: { id: 'item' },
children: [
{ tagName: 'li', props: { class: 'item' }, children: ['vue'] },
{ tagName: 'li', props: { class: 'item' }, children: ['js'] },
{ tagName: 'li', props: { class: 'item' }, children: ['html'] }
]
}When the data changes (e.g., a button reverses the list), Vue creates a new virtual DOM and runs a diff algorithm to generate a patch that updates only the parts that actually changed, avoiding costly re‑flows and repaints.
<!DOCTYPE html>
<html lang="en">
...
<div id="app">
<ul>
<li v-for="item in list">{{item}}</li>
</ul>
<button @click="change">change</button>
</div>
<script>
const { createApp, ref } = Vue
createApp({
setup() {
const list = ref(['唱','跳','rap','篮球'])
const change = () => { list.value.reverse() }
const add = () => { list.value.unshift('6') }
return { list, change, add }
}
}).mount('#app')
</script>
</html>The diff algorithm works layer by layer: it first checks if nodes are of the same type, then compares their attributes to produce a patch, and finally recurses into child nodes using a double‑ended queue to maximize reuse.
Using the loop index as a key breaks this process because the key values change when items are inserted or reordered, causing Vue to treat all nodes as different and discard the benefits of diffing. Random keys (e.g., Math.random() ) are even worse because they change on every render.
Therefore, always provide stable, unique keys (such as item IDs) when using v-for to ensure efficient updates.
Rare Earth Juejin Tech Community
Juejin, a tech community that helps developers grow.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.