Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

a component that passes slots to children forces children to rerender #5579

Open
Gagydzer opened this issue Mar 13, 2022 · 5 comments
Open
Labels
need guidance The approach/solution in the PR is unclear and requires guidance from maintainer to proceed further. scope: slots

Comments

@Gagydzer
Copy link

Version

3.2.31

Reproduction link

github.com

Steps to reproduce

I've found some cases that shouldn't makes slot-component to update, but it does. Only case #1 works properly. It looks like a bug, because it affects at lot of cases when you want to pass slots through a component to a children with this technique.

Vue.component('W', {
  props: ['child'],
  template: `<component :is="child">
  <template v-for="(_, name) in $slots" v-slot:[name]="slotData"><slot :name="name" v-bind="slotData" /></template>
</component>`
})

What is expected?

no updates in children component

What is actually happening?

it does update

@LinusBorg
Copy link
Member

LinusBorg commented Mar 14, 2022

Test 2-4 are updating because you pass already-rendered vnodes to the child, instead of a stable slot function.

However, we generally can't give 100% guarantee that all slot functions only re-render in case one of their dependencies changes. The compiler can't always be sure that a slot only depends on its own content, especially when it comes to nested slots.

So it sometimes it has to de-optimize for consistency and have the parents update their children alongside.

All That being said, Test 5 seems unnecessary so it's worth a look, but I would not be suprised if its because of the nested slot.

@Gagydzer
Copy link
Author

Thank you for your explanation.
I rewrote test 2 according to official documentation.
Those 2 examples are equivalent (according to docs), but the case with a render function still makes the child component re-render. Bug?

<InnerChild> <template #test="scope"> {{ scope.foo }} </template> </InnerChild>

() => <InnerChild>{{ foo: (scope) => scope.foo }}</InnerChild>.

And it would be nice if we could just pass slots to children this way without loosing an optimization.

setup(props, { slots }) { return () => h( InnerChild, { }, slots, ) }

Because now the best solution of this problem to avoid using slots API and pass render functions with props.

@LinusBorg
Copy link
Member

LinusBorg commented Mar 16, 2022

I must have been sleep-deprived when I wrote my initial reply as none of the the examples in the repo are actually passing pre-rendered vnodes. Sorry.

Will need to take a closer look, but likely, Evan will have to dig into this as this part of the codebase is pretty complex in terms of interactions that are happening.

But my general point still stands - we sometimes can't ensure that a slot is actually stable and so parents have to trigger re-renders in children. This is more often the case when using pure render functions as those don't contain the compiler-generated optimization hints.

Maybe there's room for improvement in providing helpers to add those manually.

@bonilka
Copy link

bonilka commented Aug 15, 2022

I met same problem. I created repository for reproducing.

Demo shows input with available clickable options. If you click on one of element, you'll see that update hook will called on each element. (It shows on page Children updated and in console).

If remove slot tag in components/MyDropdownList.vue, children wont's update.
On big lists and nested templates with component-like this in my project I have very low performance.
Maybe someone has workaround?

@Gagydzer
Copy link
Author

Gagydzer commented Oct 7, 2022

@bonilka to workaround this problem you always can avoid using slot api, just pass render function that would return VNode and render this VNode in a component template

https://stackoverflow.com/questions/49352525/can-you-render-vnodes-in-a-vue-template

@LinusBorg LinusBorg added scope: slots need guidance The approach/solution in the PR is unclear and requires guidance from maintainer to proceed further. labels Oct 7, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
need guidance The approach/solution in the PR is unclear and requires guidance from maintainer to proceed further. scope: slots
Projects
None yet
Development

No branches or pull requests

3 participants