Subscribe on changes!

Keyed elements are discarded

avatar
Sep 5th 2020

Version

3.0.0-rc.10

Reproduction link

https://codesandbox.io/s/keyed-elements-are-discarded-demo-jfuoz?file=/src/App.vue

Steps to reproduce

Create two elements of equal type.
Give the elements different keys.
At runtime, switch the keys of the elements around, so that the first element in the template now has the key of the second one, and vice versa.

What is expected?

The elements should be reused.

What is actually happening?

The elements are discarded and new ones are created in their place.


In the repro, I've set it up to keep a reference to the initial elements, and compare them to the current divs being used.
If the elements were reused, the computed values should toggle from true to false on each click of the button, but they're only true initially, and then they stay false forever.

The same can also be observed in these demos set up by Ranseur of the Vue Land discord.
Vue 2: https://jsfiddle.net/0pnujhbx/1/
Vue 3: https://jsfiddle.net/vs8Lyc3o/1/
The elements are reused in Vue 2, but discarded in Vue 3.

avatar
Sep 6th 2020

Just added here for the record: the optimization mode doesn't have a mechanism to reuse DOM, and the patchBlockChildren is just a one-to-one diff, we cannot guarantee that the VNodes in dynamicChildren are at the same level, so there is no way to achieve key-based reuse. I thought of a solution: due to a Fragment with KEYED_FRAGMENT flag will always patch its children, if there are Element nodes with the dynamic key in children, then we need to wrap the children with a fragment with KEYED_FRAGMENT flag.

avatar
Sep 14th 2020

Unfortunately this will be the expected behavior in Vue 3 due to how templates are now compiled differently to enable better update performance. In brief, template node structures are always treated as "stable" and key can now only force replacement of the a node itself, but can no longer enforce reuse of nodes that are in different static locations in the template.

This is a borderline breaking change, since using key to enforce reuse of non v-for nodes isn't technically a documented behavior, and while the behavior is different, the end rendering output isn't "wrong".