`updated` is called but component wasn't updated (different from Vue 2)
Version
3.0.0
Reproduction link
https://jsfiddle.net/7revor/xw0tLp65/42/
Steps to reproduce
1.Open the console.
2.Click the update button.
3.Observe the logging.
What is expected?
Child component would not have updated.
What is actually happening?
Child component updated.
This is expected, it did update. It wouldn't trigger with nested components though
This is expected, it did update. It wouldn't trigger with nested components though
This is actually a breaking change from v2.
In the process of migration, the resulting performance loss makes me very confused.
We have a huge amount of data, and each of them needs to be controlled whether it is displayed or not.
In v3, it takes an extra 150 milliseconds per second on computing useless rendering, and our FPS decreased from 60 to 50.
I suggest this should be documented.
It's true the behavior is different from Vue 2 and I'm not even sure it makes sense for it to call the updated
hook
It's true the behavior is different from Vue 2 and I'm not even sure it makes sense for it to call the
updated
hook
In v2, it seems that component would not update even the v-show changed (update display:none only). But in v3, no matter the v-show changes or not, as long as the parent component updated, the child component will render again(there are no props changes).
as long as the parent component updated, the child component will render again
That sounds like v2 behaviour if you used $attrs
in the child.
If I'm reading it right, shouldUpdateComponent
will return true
if there are any directives present on the VNode:
So any 'custom' directive would cause the same problem.
It took me a long time to figure out that this is what was killing performance in my app.
I am rendering ~3000 custom components (each rendering one SVG element) via v-for
and had a v-show
directive on the same elements that rendered via v-for
. Clearly having that v-show
leads the check (which @skirtles-code quoted) to succeed, so there are vdom update checks happening for all of those 3000 child components even when no data changes that are relevant to them happen.
I then followed this hint,
It wouldn't trigger with nested components though
basically just by extracting the <my-child v-for="element in myList" v-show="element.show" />
to an intermediate container component, <my-children :list="myList" />
, whose template basically just repeats that <my-child v-for...
, but as a consequence isolates it from the containing parent (where every irrelevant data changes were triggering updates). It now renders the exact same DOM elements, and only differs in the structure of the Vue component organization.
With just that, performance went up from super janky (~20fps) to almost 60fps for me!
I think enhancing this would benefit users with a similar use case like mine greatly, i.e., users who want to render large amounts of (list) data with mostly localized changes. I almost would have gone to migrate my Vue3 app to Vue2 (which I do not know) or would have dropped Vue altogether, if I hadn't found the info in this GitHub issue. Or maybe a temporary note in the docs that mentions/discusses this quirk could be added to this doc section https://v3.vuejs.org/guide/component-edge-cases.html#controlling-updates ?
Thanks for the hints everyone!