Subscribe on changes!

Scoped Slots was not used, but the slots were re-rendered anyway

avatar
Nov 10th 2022

Vue version

3.2.44

Link to minimal reproduction

https://sfc.vuejs.org/#eNqdkb9OwzAQxl/F8tJUbewKyhLSqggWVmYvoXFpIP4j+5IOUTbgcRiRUF+Hitfg3H+UInVgyHD3/fJ957uGXlnL6krShKZ+6goLxEuo7FjoQlnjgDR+npWlWdzJWUtmzijSQb5zuQeujbJbgfFQBL+gp3zjiF5YgFS2zECGCgSkgRx/LZ8/l++r15fV20fcNDeoM20WUbdt07UX0inf/0r7dBMaq8yyR280zt0ITYjYCl7QhKw7oYeDhFrQOYD1CeeVtk8PbGoUn6DGXaWhUDLOjZqcszM2HPK88HDYZ9Kr+N6ZhZcOEwXtH5hzbNbSxU7qXDrpToYdsb8Cj7Q/oSGzFbrFBew2/J+LCT012gOps3L0A0WDLmpocqsB58jKKOqS0TisUUCvhw2GXyURavsXgzV94rZpXtS7I/vSAEnyDLIRLiwrBeUbBp8doMPbtt9fS+oB

Steps to reproduce

1.The time stamp for viewing the page is constantly updated

What is expected?

The timestamp should be static because my slot doesn't use any response variables

What is actually happening?

The time stamp for viewing the page is constantly updated

System Info

No response

Any additional comments?

No response

avatar
Nov 10th 2022

I'm not sure what behavior you are expecting or what you mean by "scoped slot was not used".

slots are functions. passing a prop to a slot will call that function, regardless of wether or not use actually make use of the passed argument in it. And your components all constantly re-render because you constantly change reactive state that is then, in each-render passed to the slot.

avatar
Nov 10th 2022

I'm not sure what behavior you are expecting or what you mean by "scoped slot was not used".

slots are functions. passing a prop to a slot will call that function, regardless of wether or not use actually make use of the passed argument in it.

组件内容-{{Date.now()}} Is static, does not have any reactive variables, it should not be called again. I use vue2 locally and it won't update image image

avatar
Nov 10th 2022

Talking about the first, original example:

  • <Comp> /> can't know the content of the slot until it has run the slot function.
  • and it needs to re-run the slot function over and over because <Comp > re-renders over and over
  • because you change reactive state over and over with the timeout.

You can see in your other examples that there, the slot is not being re-run because the respective nested component doesn't need to update.

avatar
Nov 10th 2022

The same code is updated for vue3, but not for vue2. You can run the code into a vue2 project and you will see that the slot will only run once

avatar
Nov 10th 2022

@LinusBorg And I think it can be done. It's like computed. The responsive variable is tracked the first time it is run, and then re-run when the dependency is updated, otherwise it is returned directly to the cache

avatar
Nov 10th 2022

The same code is updated for vue3, but not for vue2. You can run the code into a vue2 project and you will see that the slot will only run once

yes. Because in Vue 3, slots are functions, returning vnodes. in Vue 2, normal slots are just an array of pre-rendered vnodes, received from the parent.

But there should be no performance difference for the shown use case, because in both ways, a re-render results in new vnodes being created for each slot when <Comp /> re-renders.

  • in Vue 3, the slot function runs and returns new vnodes
  • In Vue 2, the old vnodes are cloned.
avatar
Nov 10th 2022

@LinusBorg You can't just think about the performance of creating vnodes. You can imagine if it wasn't Date.now and a more complex function was very time consuming. The performance bottleneck here is this function, so the performance gap between vue2 and vue3 is huge

avatar
Nov 10th 2022

a more complex function was very time consuming

That doesn't belong into the template, plain and simple.

avatar
Nov 10th 2022

@LinusBorg This is just for illustrative purposes, wherever this function is, the re-rendering of vue3 will inevitably result in its execution. I just want him to reuse the previous vnodes instead of generating new vnodes, which can be time-consuming

avatar
Nov 10th 2022

There should be no heavy logic executed in templates, slots or not. As long as you don't do that, running a slot function again vs. cloning the slots old vnodes will be practically the same, maybe even faster due to Vue's optimized render functions.

If you can share a practical example that has a noticeable performance impact without running any heavy code in the slot itself, please share it.

avatar
Nov 10th 2022

@LinusBorg Can I share my project with you, I wrote a virtual scroll component in it, I think it should explain the problem

avatar
Nov 10th 2022

Depends on how big it is. It should be reasonably focussed on the problem to demonstrate. But yeah, let's try, I'm curious.

avatar
Nov 10th 2022

@LinusBorg Please wait a moment while I write a simple example and give you a git address

avatar
Nov 10th 2022

@LinusBorg https://gitee.com/tangguoxiong/powerful-ui/tree/test/

  1. Download the project

  2. Switch to the test branch

  3. npm i

  4. npm run serve

  5. You can see that the page has a list of 500,000 data

  6. Punch in the console and scroll through the list a little

  7. You find that the slot is rendered hundreds of times

avatar
Nov 10th 2022

The code for the page is in "doc/App.vue"

avatar
Nov 10th 2022

That example uses scoped slots (and is using their slot props), which are functions in both Vue 2 and Vue 3. and of course a virtual scroller rendering dozens of lines at a time through a scoped slot will render the slots function hundreds of times when you scroll around a huge list.

I'm not sure what this is intended to show in relation to this issue.

FYI: For a performant virtual scroller, you can take a look at

avatar
Nov 11th 2022

This is expected behavior. Slots do not have their own tracking scope, they are rendered as part of the child component's tree. If the child component is updated, any slots it uses will be called as well.

This cost can be avoided in more granular systems like vapor mode which we are exploring for the future, but not in VDOM based systems.