Vue: v-for : add a prop 'uniqueKey' to generates a unique key automatically

Created on 27 Jul 2017  ·  28Comments  ·  Source: vuejs/vue

What problem does this feature solve?

In our business system, there is so many :key object used.
We did so many data operate, we have to use it.
And now, object key is not advocated, and I'm wondering if there is some prop can do it automatically.
It's will be helpful.

What does the proposed API look like?

<div v-for="item of list" :unique-key="true"></div>

Most helpful comment

You can use the index for this (this is if you don't care about Vue reusing the elements or components). Keep in mind key is not always required

<div v-for="(item, index) in items" :key="index">
  <!-- content -->
</div>

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

All 28 comments

You can use the index for this (this is if you don't care about Vue reusing the elements or components). Keep in mind key is not always required

<div v-for="(item, index) in items" :key="index">
  <!-- content -->
</div>

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

@posva , you can see this issue : https://github.com/vuejs/vue/issues/5410

@yyx990803 :

You are using the index as the key... which is the same as no key at all. You should give each of your data objects a unique id so that they can be keyed properly.

vue

@posva ,I know, if there a show list, we don't need it, but we has so many edit things.

@vvpvvp, that's the point, we vue can not know how developer wants key to work, index is unique key example but most of the time it's not what you are looking for, how can Vue know what you wanted?

@nickmessing , I just want v-for has no question when i use it normal.
for example, I wrote an common table component , and it used v-for list data, and have some operate staffs, we don't know data's key prop, or there is no key completely.
how can I do, I used object as key.
but now, it's not advocated.

and, If I don't use key, there is some problem we not expected.
you can see this issus: https://github.com/vuejs/vue/issues/5408

I thought you were forcing yourself to use a key. You don't always need keys
You need unique keys for your objects, you probably have some kind of id. as @nickmessing said, Vue cannot guess it for you... Its guess is using the index

@posva , I thought you are missing this point :

You are using the index as the key... which is the same as no key at all. --- from yyx990803.

I don't want force myself to use a key, it's because if I don't use it, it will be something wrong.
link: https://codepen.io/vvpvvp/pen/oZKpgE
steps:
1: click "add" twice
2: click the last line 'click me'.
3: click the first line 'delete'.

that's why I told you to use the index... because it should be the same...
You can generate a unique id with every object, and in your case, you need it. That's what we're trying to tell you

Hi @vvpvvp
as @posva said you should generate a key
workaround by https://github.com/puleos/object-hash
eg: https://codepen.io/anon/pen/NvGwyQ

@vvpvvp , the point is Vue cannot infer a unique key for you, what vue can do and already does is to infer a key based on index.

If there are operations like "add" or "delete" elements in list, you really should generate a unique yourself. A simply counter could do the trick.

@Kingwl , I understand.
so, I have a question, what's the difference between we generate and vue generate.
why not vue do it by itself, yes, you don't know what we want, so I told you, I has no key in my data when I use v-for, and I need edit some data or do some thing else, and could you please generate unique keys for us?

@vvpvvp calm down my friend 😅
generate unique keys is so complex to cover all case
and it not too hard to generate a unique key by user

and IMO this behavior is not normal...i(we) will try to improve it
have @yyx990803 got some advice?

Vue cannot generate the unique keys for you because it doesn't know how or when you add or delete items. But it's super easy to add an id. Without using hash you can use an incrementing id: https://codepen.io/posva/pen/BdoJJz

he told you that is a unexpected behavior not expected behavior 🌚
and add a key can resolve that

IMO the feature of supporting object type keys is more constructive than this, and it's likely to be implemented in the future. See https://github.com/vuejs/vue/issues/5804#issuecomment-305950427

As you know, the unique key must be attached to the item object, when it's automatically generated inside Vue, it may cause some problems if users are unaware of that.
If you really feel troublesome to generate unique ids for objects by yourself, you can write a common util function to achieve it. It's similar to the workaround @Kingwl provided, but much lighter (and may lead to a performance issue😂, you can test it in your App):

const UNIQUE_KEY_PROP = '__unique_key_prop__'
const KEY_PREFIX = '__key_prefix__' + Date.now() + '_'
let uid = 0

const isObject = val => val !== null && typeof val === 'object'

const genUniqueKey = obj => {
  if (isObject(obj)) {
    if (UNIQUE_KEY_PROP in obj) {
      return obj[UNIQUE_KEY_PROP]
    }
    const value = KEY_PREFIX + uid++
    Object.defineProperty(obj, UNIQUE_KEY_PROP, { value })
    return value
  }
  return obj
}

Vue.mixin({
  methods: { genUniqueKey }
})
<div v-for="item in items" :key="genUniqueKey(item)">

Here's a demo - https://jsfiddle.net/xujiongbo/3wt7hv7c/

By default, Vue uses the index of the items since it's the only thing it can do without having to "guess" what the developer wants.
Vue won't generate unique keys for you, there is no point in this. The developer needs to provide unique keys because Vue can't guess them. Also, Vue mutating your objects on its own would be very wrong in my opinion.
If your data don't have any field that could be used as unique keys, there is something not right about it, ask your backend team.

@posva ,

But it's super easy to add an id.

no..........

1st, it' s ugly.

2nd, it's easy to add an id in a simple demos. but, it's not easy to add an id in our complex datas with complex system. and the data is nested structure. and it's nested and nested and nested...

finally, it 's good in vue1.0 , and we don't need key at all, I know vue mechanism changed, I just wonder if there is some way can handle it, it will be so helpful.

tips: it's not only v-for problems, some adjacent element with directive used, if you don't add some key, it's also has some problem.

@Kingwl , my English is not good, maybe my words is not readability, I'm sorry about it, but I am also peaceful.

1st, it' s ugly.

Why?

2nd, it's easy to add an id in a simple demos. but, it's not easy to add an id in our complex datas with complex system. and the data is nested structure. and it's nested and nested and nested...

Don't you have fields in your data to make them unique? How do you make the relations between your objects?

finally, it 's good in vue1.0 , and we don't need key at all

If you want the default behavior, you can just use the index:

<MyComponent v-for="(item, index) of items" :key="index"/>

Note that you don't need this if you are looping over HTML standard elements.

I wrote very slowly, so when i complete my answer, always a new answer to me.

@javoski , you are so kindly, function genUniqueKey, I can wrote it myself, there is no problem at all.

vue can't change the datas we define, and also I can't change the data used on my ui components, like table component and so on.

I wrote an ui toolkit with vue2.0, http://www.heyui.top/component, if i used kind of genUniqueKey function, maybe i can do, but it's too hard, and i really don't like the way.

@Akryum , I don't want to answer it so many times. index is not useful, please read this demo .

link: https://codepen.io/vvpvvp/pen/oZKpgE
steps:
1: click "add" twice
2: click the last line 'click me'.
3: click the first line 'delete'.

@vvpvvp I was answering just a part of your comment. As you should know by now, your issue will be resolved when you will provide a unique key for each item in your data.

Let's move the discussion to the Discord server (or the forum). Other people will be able to help you with insights that are more specific to your project @vvpvvp 🙂
Thanks

@vvpvvp I came to a similar situation using Vue components inside a list that it can be edited (add/remove items and change the order using VueDraggable). Items haven't any unique id because they are generated data within a form. The solution I've found is to use a "shadow" list where I save unique ids, for rendering purpose, and to edit both lists on user interaction.

Here is an example using your code
https://codepen.io/anon/pen/RZzbmM

@nauzethc, thank you very much.
I must explain that I know all this solution about solve this question.
But It's will be better if we don't need a key In the ordinary way.
It's not a problem when we use v-for, I met so many inexplicable problems in my development.

@vvpvvp, i understand your problem.
The main problem with key here is if your data realy have unique ids but, when you create new items in list/table you add them with blank ids like 000-000, then when it goes to server it generates proper uids.
But as far as your are in edit mode and adding new items you don't realy want to generate ids for them, server needs em as blank, so to handle this problem you have to add another one ids and that's not realy something you want.
Adding an option that would generate keys for inner Vue use seems legit request.

I came across this issue and resolved it by adding "key" attribute with Date.now() value as a key.

e....
good solution?
It's mean you give up use “in-place patch” strategy

@mohd-isa
It's unsafe method. Iteration loop may take place more than one in the same Date.now() period.
Look: http://snpy.in/pjuT8K
Date.now() used in screenshot.

Actually, the problem appears in cases we can't get UID from item; items could change (they come as a props for ex.); they should take place simultaneously (transition-group, for ex.).
Thats the point – we can't set simply index, or my-awesome-item${index}, etc.

IMO, the best way is provide build-in mechanism for generating UIDs. That isn't hard to write helpers, it's hard to do it every time in every project.
Just include generator to the Vue core or add helpers (we just have Map-helpers in Vuex, why not?).

Please refer to https://vuejs.org/v2/guide/list.html#key to see all the implications about setting a key and why Vue needs it for component.
Using Date.now() for keys is a very bad idea as it will tell Vue to never reuse components.
Most of the time using the index of the iteration is fine but if your component have a state and the list may change (new elements, removed, reordered), make sure to use an _id_ that uniquely represents the object that is passed to your component. For example: if you have a contact component that displays a contact information and has a contact prop, use the id of the contact (usually coming from the db) as the key:

<Contact v-for="contact in contacts" :contact="contact" :key="contact.id" />

A built-in mechanism to generate UID have no place in Vue as it is not related to building interfaces.
Sometimes you can use other content that is unique like names. A cleaner way if to generate a new version of your list that augment your items with UIDs

Was this page helpful?
0 / 5 - 0 ratings

Related issues

lmnsg picture lmnsg  ·  3Comments

guan6 picture guan6  ·  3Comments

bfis picture bfis  ·  3Comments

robertleeplummerjr picture robertleeplummerjr  ·  3Comments

loki0609 picture loki0609  ·  3Comments