vuejs / core

🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
https://vuejs.org/
MIT License
46.94k stars 8.24k forks source link

$slots not reactive outside template #11240

Closed geiregjo closed 3 months ago

geiregjo commented 3 months ago

Vue version

3.4.30

Link to minimal reproduction

https://play.vuejs.org/#eNqtVNtu2kAQ/ZXpNlJASu1W6RM1SFzy0D40VZNHS5UxAywxa2t3DUSIf+/smvUFA5GivO3OmXPmsjuzZ8Ms8zY5sh4LVCx5pkGhzrNBKPg6S6WGPUicwwHmMl3DLbneltBTkupxSmeBQh8dPL9hNdpECEWcCkXahA2hbyQ7WubYrQOjS8D4EjBpAoFflEDJ00XjOksijXQDCJbfBiYxBZFEEKkmXhRrvkHYLlFArnAGW66XXEAEMaWfa7JsIsmjaYKfAp8ErFA2eE4XiwRtAoqIXCxALxHiJcYv03SHyoPHqUJJ2qVQ4Wzi5tks0sTxAt90mRQbDbMmMrrs4XPRs80XPu+HzF5CNhgGfqO+FmNUZ4yIMXqLMa4zxsQYv8WY1BkTYkxOGEHzM9h3IWsSTTFxklxQh0C/ZkhCrochI+l1OsOkqhn8I+XYfyMNwyJMpWjvU2md3xuM2nU22KgZ7CNCUZ/Phhp/fCh6oLOhJs1QjSdkd0wrmrc5X3grlQpaE3vbZWZ+Nk9QPmaa0zyGrAcWMViUJOn2l7WZybxzdpvaGftKUbY9OvyRaOcmZCWmI7lAXcAPT79xR+cSpPLyhLyvgH9RpUlucizcRrmYUdo1P5vtT7vRaCyf1cNOo1CuKJOo8TxY/5DRPjP/+VLpVbr33nfLC8WButhaitcWrtsad2Yt2a11XL82fMh+VAv1xnnQJnTHTpccjrCTcj7u3ul0oT+gPbXCWHsv+Ko6pVTX8K/s0ptimXWcsUv175tS1qMLB6q++rgVs4zUZpbQRbIroSCfVHgkzfjGDYdhgYjWZjZON0kLrE9+C6zPaguspivwi+ing/Rvg9J8K3p5+hve/Vd2+A8Y1oHi

Steps to reproduce

Toggle slots using the checkboxes. Observe that the computed $slots are not updating.

What is expected?

Expect computed variables depending on $slots to react to $slots changes.

What is actually happening?

Computed variable depending on $slots is not reacting to the $slots change.

System Info

No response

Any additional comments?

No response

linzhe141 commented 3 months ago

Because instance's slots is not a reactive object, but a normal object

image

geiregjo commented 3 months ago

However, it is reactive when used in a template?

LinusBorg commented 3 months ago

However, it is reactive when used in a template?

It's not, actually. When the parent changes the number of slots it passes down, it tells that child component "hey, you need to re-render". And during that re-render, triggered by the parent component, not by the slots object, you read the sot object's properties again. That's why they are updated in the template.

geiregjo commented 3 months ago

Ok, I'll use onBeforeUpdate to detect slot changes then.

Just wondering, is this worth a feature request?

linzhe141 commented 3 months ago

However, it is reactive when used in a template?

The componentUpdateFn of the component will update the slots and execute the render function when it is re-executed, so the slots in the render function are the updated slots.

image

image

skirtles-code commented 3 months ago

There was a similar issue opened recently, #11227. The description of the problem is different, as is the use case, but I believe the underlying cause is the same: the slots object isn't reactive and is being used outside the rendering of its owner component.

I'm wondering whether the decision to make the slots object non-reactive should be re-evaluated. I think it made sense back in a Vue 2 Options API context, but maybe it isn't such a good fit for where Vue is now?

It feels similar to $refs and $attrs. Previously they were just plain objects, but that didn't work well with the Composition API, so they've both been 'replaced' by alternatives that support reactivity, or at least partial reactivity.

I assume the reason it isn't reactive is because of the extra overhead, but is that really significant enough to worry about if it makes slots more difficult to use in more advanced use cases?

I also wonder whether making slots reactive might benefit Vapor mode.


Bit of a tangent, but more generally I wonder whether the current approach of forcing a child to re-render when the props or slots change is actually the best way to go. While I can understand why it was done that way, it is a problem I've hit a few times and it can be really difficult to work around.

Perhaps, rather than always forcing a re-render, it could check whether the relevant job has been added to the scheduler queue and only do the re-render if it has? That approach might already be viable for props, though for slots it would need reactivity adding to the slots object.

yyx990803 commented 3 months ago

closing as a duplicate of #11227 as the root cause is the same.