Subscribe on changes!

$slots/useSlots reactivity breaks if same component with different content

avatar
Jun 29th 2022

Vue version

3.2.37 | @8edf4b3

Link to minimal reproduction

Repro 1 Repro 2

Steps to reproduce

Changing reactively the template for a slot with the same child component but with different content breaks reactivity of useSlots/$slots/setup context slots:

<script setup>
import { ref } from 'vue'
import Comp from './Comp.vue'
import Comp3 from './Comp3.vue'

const data = ref(0)
setInterval(() => {
  data.value++
}, 1000)
</script>

<template>
  <h1>{{ data }}</h1>
  <!-- BUG? Doesn't update properly -->
  <Comp3>
    <template v-if="data % 2 === 0" #actions>
      <Comp>
        <template #foo>
            {{ data }}
        </template>
      </Comp>
    </template>
    <template v-else #actions>
      <Comp>
        <template #foo>
        </template>
      </Comp>
    </template>
  </Comp3>
</template>

What is expected?

The computed calling slots.foo should be re-evaluated when the content changes.

What is actually happening?

It's not updated and the computed value is stuck.

System Info

No response

Any additional comments?

Related: Slots improvements RFC

avatar
Jun 29th 2022

Commenting because we've come across a similar issue/bug since upgrading from 3.2.33 => 3.2.37

avatar
Jun 30th 2022

due to the diff algorithm, you should add unique keys to differentiate these two <Comp>

<Comp3>
    <template v-if="data % 2 === 0" #actions>
      <Comp key="1">
        <template #foo>
            {{ data }}
        </template>
      </Comp>
    </template>
    <template v-else #actions>
      <Comp key="2">
        <template #foo>
        </template>
      </Comp>
    </template>
  </Comp3>
avatar
Jun 30th 2022

Having different content should work without having to use keys.

avatar
Jul 13th 2022

Here is a better example.

avatar
Sep 2nd 2022

Glad to see this closed, but the fix 00036bb seems to break vuepress build. After downgrading vue version to 3.2.37, the error disappeared. Does this change affect template syntax?

avatar
Sep 30th 2022

Repro 1 is not resolved by the fix

avatar
Oct 14th 2022

Repro 1's root cause is that slots isn't reactive, similar to attrs.

Workaround example using a manual ref for fooSlot and update it in onBeforeUpdate (see Comp.vue)