Unintended data exposed
Vue version
2.6.11
Link to minimal reproduction
https://codesandbox.io/s/sweet-fast-xk4dl3?file=/package.json:262-268
Steps to reproduce
Press the add button
What is expected?
Both the upper and lower regions must be exposed with the same prop and local data
What is actually happening?
The area below is normal, but the area above shows different values of prop and local data
System Info
No response
Any additional comments?
No response
I think this StackOverflow answer has explained the issue well: https://stackoverflow.com/a/75175749/2302258 Generally, using the array index as the key is a bad idea.
@sodatea
Thank you for your reply. But I don't think the link explains everything.
because
When the key is set to :key="${index}-${member}"
1-tomato 2-tomato 3-tomato key is set
After all, isn't this:key="index"
and :key="${index}-${member}"
the same thing?
It's about the patching algorithm: https://v2.vuejs.org/v2/api/#v-for
The default behavior of
v-for
will try to patch the elements in-place without moving them. To force it to reorder elements, you need to provide an ordering hint with thekey
special attribute:
Let's walk through the demo step by step:
- Originally, the first list item is
Prop: apple | Local Data: apple
, the index is 0 and the name isapple
. - In the
:key="index"
case:- The original key was
0
- After unshifting
orange
to the array, the first list item becomesorange
, yet the index is still 0; - The new key is
0
- So Vue sees the two keys are identical; the item should be patched rather than removed-then-recreated;
- So
mounted
isn't called.localName
stays asapple
; - Vue rerenders the component with the new prop value and applies it to the real DOM. The list item becomes
Prop: orange | Local Data: apple
- The original key was
- in the
:key="${index}-${member}"
case- The original key was
0-apple
- After unshifting
orange
to the array, the first list item becomesorange
, yet the index is still 0; - The new key is
0-orange
- Vue sees two different keys; the item must have changed. The existing one should be removed
- A new list item is created. The
mounted
lifecycle hook is called,localName
is in sync with the latest prop value.
- The original key was
It might be easier to understand if you:
- add an
<input>
in the<li>
- type something in each input
- then click the
add
button - see which inputs' states are preserved, and which are not
@sodatea
Thank you for your answer
But I have another question
As shown in the video attached below, if you keep putting the same input value, isn't the situation where the keys overlap the same? (0-orange)
https://github.com/vuejs/core/assets/47649108/9b49bd15-df21-4c2d-82e8-9a2de71485f0