When working with v-for in Vue it is typically recommended to provide a special
key attribute. Something like this:
<div v-for="item in items" :key="item.id">
The purpose of this key attribute is to give "a hint for Vue's virtual DOM algorithm to identify VNodes when diffing the new list of nodes against the old list" (from Vue.js Docs).
Essentially, it helps Vue identify what's changed and what hasn't. Thus it does not have to create any new DOM elements or move any DOM elements if it doesn't have to.
Throughout my experience with Vue I've seen some misunderstanding around the key attribute (as well as had plenty of misunderstanding of it on my own) and so I want to provide some tips on how to and how NOT to use it.
First and foremost my best piece of advice is this: just provide it as much as humanly possible. This is encouraged by the official ES Lint Plugin for Vue that includes a
vue/required-v-for-key rule and will probably save you some headaches in the long run.
Ok, so I should use it but how? First, the key attribute should always be a unique value for each item in the array being iterated over. If your data is coming from a database this is typically an easy decision, just use the
uid or whatever it's called on your particular resource.
<div v-for="user in users" :key="user.id">
But what if the items in your array don't include an id? What should the key be then? Well, if there is another value that is guaranteed to be unique you can use that.
<div v-for="user in users" :key="user.username">
Or if no single property of each item is guaranteed to be unique but a mixture of several different properties is, then you can JSON encode it.
<div v-for="user in users" :key="JSON.stringify(user)">
But what if nothing is guaranteed, what then? Can I use the index?
You should not use array indexes as keys since indexes are only indicative of an items position in the array and not an identifier of the item itself.
❌ <div v-for="(user, index) in users" :key="index">
Why does that matter? Because if a new item is inserted into the array at any position other than the end, when Vue patches the DOM with the new item data, then any data local in the iterated component will not update along with it.
This is difficult to understand without actually seeing it. In the below Stackblitz example there are 2 identical lists, except that the first one uses the
index for the key and the next one uses the
user.name. The "Add New After Robin" button uses splice to insert Cat Woman into the middle of the list. Go ahead and press it and compare the 2 lists.
Notice how the local data is now completely off on the first list. This is the issue with using
Let me let you in on a secret, leaving it off is the exactly the same thing as using
:key="index" . Therefore leaving it off is just as bad as using
:key="index" except that you aren't under the false impression that you're protected since you provided the key.
So, we're back to taking the ESLint rule at it's word and requiring that our
v-for use a
However, we still haven't solved the issue for when there is truly nothing unique about our items.
This I think is where most people really get stuck. So let's look at it from another angle. When would it be ok NOT to provide the key. There are several circumstances where no key is "technically" acceptable:
While these scenarios do exist, often times they can morph into scenarios that don't meet said requirements as features change and evolve. Thus leaving off the key can still be potentially dangerous.
In conclusion, with all that we now know my final recommendation would be to:
Leave off key when: