V-for with simple arrays: what key to use?

The following code shows how I use v-for with simple arrays that have single-item non-object values. It looks problematic, though — since I’m using array items as keys, and thereby (I think?) negating the value of a key.

I’d like to know how people use v-for with such simple arrays. I think these are the options I have. The first option means there’s no place for simple arrays. What about the last two?

  1. Use arrays of objects instead, explicitly declaring a key for each item.
  2. Don’t use a key in the v-for.
  3. Use item’s index as the key.
  4. Use item itself as the key.

Within <template>:

<ul>
    <li v-for="fruit in fruits" :key="fruit"></li>
</ul>

Within <script>:

export default {
    data() {
        return {
            fruits: ['apple', 'banana', 'orange']
        };
    }
};
3 Likes
<ul>
    <li v-for="(fruit, index) in fruits" :key="`fruit-${index}`"></li>
</ul>

You can do destructuring as well. Let’s say fruits was an array of fruit objects with a name and a price:

<ul>
    <li v-for="{name, price, id} in fruits" :key="id"></li>
</ul>
12 Likes

I would suggest using option 2 (don’t use a key). It depends on the type of content, but I’m guessing that the default “node-diffing” algorithm that Vue uses would be most efficient in your case. This is what the docs say about when to define a key:

This default mode is efficient, but only suitable when your list render output does not rely on child component state or temporary DOM state (e.g. form input values).

For example, this example would require a key (in fact, you get an error in the console if you don’t):

<custom-component v-for="(item, index) in items" :key="index"></custom-component>

But this one is better without:

<p v-for="item in items">{{ item }}</p>

For more info: https://vuejs.org/v2/guide/list.html#key

5 Likes

Thanks. In your custom-component code, you used index as the key. Is that OK under all circumstances? If so, I wonder why vue doesn’t do so automatically (in those contexts where a key is necessary).

I’m not sure if your first option is in any way better than just using index.

I want to avoid having to create objects where they’re not necessary otherwise. So your second option doesn’t really solve the issue. But I like the destructuring idea for objects.

1 Like

Are you talking about me adding the prefix to the index? I did that to show ways to unique-ify plain indices when you have to render out multiple list-based components in the same context.

Using index as the key works, but no it’s not ideal. It’s better to use something that is actually tied to the item. The docs give a good explanation of what an ideal key would be:

An ideal value for key would be the unique id of each item.

This allows Vue to reorder the existing elements if they change position in the array.

One option when you aren’t using id’ed data is to pull in something like lodash’s uniqueId method and add it as a global mixin. Then you can go crazy id’ing things!

Maybe I’m misunderstanding, but I don’t see how that makes any difference. 0, 1, 2 will become fruit-0, fruit-1, fruit-2, and so on.

lodash’s uniqueId seems a great suggestion. I’m going to explore it.

E.g. you have a list that get its content changed.

e.g.

let data = [1,2,3,4]
<div v-for="(number, index) in data" :key="index">
// Which turns into number - index:
1 - 0
2 - 1
3 - 2
4 - 3

Now if you remove number 2, the index information is worthless, because everything after 2 gets a new index:

1 - 0
3 - 1
4 - 2

And this does not work. 3 and 4 will lose their state and have to be re-rendered, instead of just removing 2.
Which is why you should use a unique ID.
with lodash IDs, it doesn’t matter that much either - depending on where and when you add those IDs. But you might as well just number your items with their index.
It is just important that they keep their index number and not get re-assigned on every change.

5 Likes

What do you mean by “…number your items with their index…”?
How do you do this? Aren’t the index’s automatic? Even if they get re-assigned?
How do you “number your items with their index” so that a re-assign is prevented?

Thanks for the information.

If you have an array of objects that represent some data from a database, each object probably has a unique id used to identify it for updating, removing, etc.

For example, names = [ {id: 1, name: "one"}, {id: 2, name: "two"}]

By giving Vue the id to use as its key, it can efficiently update the DOM for just the changed objects instead of re-rendering all the DOM nodes associated with the list.

<li v-for="{id, name} in names" :key="id">{{name}}</li>

That :key=“index” thing can give you problems.
For example, I have a list of items that you can delete (each item with a delete button), when you click several delete buttons it handles the async call to the api and then deletes the item on response.
My app deleted wrong elements. Not the elementes I clicked…
Updated to :key=“item.uuid” and problem solved.