Could someone explain what is the difference between those 2 v-for structures:
<li v-for="item in items" :key="item">
</li>
and
<li v-for="(item, i) in items" :key="i">
</li>
Could someone explain what is the difference between those 2 v-for structures:
<li v-for="item in items" :key="item">
</li>
and
<li v-for="(item, i) in items" :key="i">
</li>
Vue requires all items inside a v-for to be "key-ed". The key is used to uniquely identify each element. This doesn't mean Vue will break if you don't use a key. It will warn it might not be able to detect all changes.
The "key" is particularly useful and important to Vue, as it allows it to skip re-rendering items which have not changed.
When duplicate keys are detected across a rendered collection, Vue will issue a warning.
Another Vue recommendation is that the "key"s are primitives (strings or numbers). When you specify non-primitive keys Vue will, again, issue a warning.
Given all the above recommendations, when rendering an array of unique primitives, using
<div v-for="item in items" :key="item" />
...is perfectly acceptable, as it meets the requirements: each key is primitive and unique.
Therefore, if you change the order of the items, Vue will be able to re-use the existing DOM elements and perform any move transitions (if you specified any). Testing this is actually fun. Consider this example, taken from the Vue documentation. Open it and, using dev-tools, change any of the rendered items' color to red. Then click the shuffle button. You'll see Vue re-uses the element and your custom change is kept, as the item is moved around.
When you're dealing with collections of non-primitives, or with collections of non-unique primitives, Vue still expects you to provide a unique primitive key for each item. Ideally, you should have a unique identifier (e.g: item.id). This is the typical solution and meets all requirements.
Sometimes, you don't have a unique identifier on each item, and an easy solution is to just use the items' position in the array as identifier (key):
<div v-for="(item, index) in items" :key="index" />
However, remember this can become problematic, particularly in cases where you change the order of the items after they're rendered and expect Vue to react to this change. It won't! Because Vue only watches the keys. When you swap items, keys don't change. only values do, so Vue won't re-render.
Official docs here:
As an example of how useful and powerful keys are when rendering, have a look at this virtual scroller.
Open the dev tools, inspect any cell and then scroll, while keeping the devtools open. You'll notice rows and columns only get updated when they change (each element flashes swiftly when it gets updated).
If you look into the code, you'll notice keys are dynamic. So you'd expect the first <div> in rows to always render the contents of the first object in rows and swap contents whenever another object takes first place in the array.
Thanks to the keys, Vue keeps the same <div> throughout its journey across the screen and only discards it after it leaves the scrolling window. As you scroll up, new <div>s are prepended to parent and as you scroll down new <div>s are appended, while the top ones are discarded.
This allows scrolling 100k rows (and 1 billion cells) smoothly (well, only in theory; in practice - we're only rendering as many cells as the screen can fit + 1 extra row + 1 extra column).
In the first case, the v-for iterates over all elements of items. It assigns the :key to the item itself. This is not ideal if you have duplicate elements in items, because each :key should be unique.
In the second case, v-for also iterates over all elements of items, but it introduces another variable named i, which represents the numerical index of the item in items. This index is then assigned to :key. This is better, because the indexes can't be duplicate.
As the purpose of :key attribute is to give a hint for Vue virtual DOM algorithm about change detection happen. Essentially, it helps Vue identify what's changed and what hasn't.
To understand it better I am adding the uses of both the scenarios :