Subscribe on changes!

vue update event maybe has error whit slot

avatar
Apr 25th 2023

Vue version

3.2.47

Link to minimal reproduction

https://github.com/wht300/vue-slot-trigger-update

Steps to reproduce

What is expected?

I think this may be a bug that I expect the update event of the component to be fired when both addSlotCount and addDivCount methods are called

What is actually happening?

onBeforeUpdate will be called when addDivCount is triggered. But when addSlotCount is triggered, onBeforeUpdate will not be called

System Info

No response

Any additional comments?

No response

avatar
Apr 25th 2023
watchEffect(() => {
  console.log(countOnSlot.value, countOnDiv.value);
});
avatar
Apr 25th 2023
watchEffect(() => {
  console.log(countOnSlot.value, countOnDiv.value);
});

Hi, the focus of the problem is not to get the value of countOnSlot or countOnSlot. The point should be that the inconsistent behavior of the onBeforeUpdate or onUpdated hooks in slots and regular HTMLElements will cause some buggy edge cases. For example, the useTemplateRefsList function in @vueuse/core relies on the onBeforeUpdate method. You can check another issue for the specific scenario problem. https://github.com/vuejs/core/issues/8147

avatar
Apr 25th 2023

This is by design.

when only the slot depends on a reactive value, then only the child component consuming the slot actually needs to re-render, not the parent. This has significant perfomance advantages. The logical consequence is that in such scenarios, beforeUpdate and updated hooks in the parent are not called, because the parent, in fact, did not update

avatar
Apr 26th 2023

This is by design.

when only the slot depends on a reactive value, then only the child component consuming the slot actually needs to re-render, not the parent. This has significant perfomance advantages. The logical consequence is that in such scenarios, beforeUpdate and updated hooks in the parent are not called, because the parent, in fact, did not update

Is there any way to perceive slot updates in Vue 3 currently? Scenario: I am currently using the useTemplateRefsList function from @vueuse/core which relies on the beforeUpdate feature. When I place a page in a PageLayout.vue component and use:ref="refs.set" with v-for in the page, this problem will cause el to be inserted repeatedly into refs when the page changes, like

<template>
<div>  
<LayoutWrap>
<div v-for="item in list" :key="item">
       <MyComponent :ref="refs.set">{{ item }}</MyComponent> 
    </div>  
   on slot 
  {{ countOnSlot }}
</LayoutWrap>
<button @click="addSlotCount">addSlotCount</button>
</div>
</template>  

<script setup>
import { ref } from 'vue' 
import LayoutWrap from '@/components/LayoutWrap.jsx'
import { useTemplateRefsList } from '@vueuse/core'
const list = ref([1, 2, 3, 4, 5])
const refs = useTemplateRefsList()  
const countOnSlot = ref(0)  
// Each time addSlotCount is called, the length of refs will be increased by 5  
const addSlotCount = () => {  
 countOnSlot.value++  
}
</script>

How should I avoid this problem?

avatar
Apr 26th 2023
watch(
  refs,
  async () => {
    await nextTick();
    console.log([...refs.value]);
  },
  {
    deep: true,
    flush: 'post',
  },
);

// or

watch(
  refs,
  () => {
    nextTick(() => {
      console.log([...refs.value]);
    });
  },
  {
    deep: true,
    flush: 'post',
  },
);