slots are not reactive in setup (but are in template via $slots)
Version
3.2.11
Reproduction link
Steps to reproduce
- Run repro:
yarn && yarn dev
- Click "Toggle footer component"
- Observe difference between Happy and Sad components
What is expected?
$slots.NAME
and computed(() => !!slots.NAME)
should function the same for detecting slot changes
What is actually happening?
Only $slots.name
works, slots
in the setup
context doesn't appear to trigger reactivity.
$slots isn't reactive either and never has been. This would also not work and never worked in Vue 2 as well:
<script>
export default {
computed: {
hasFooter() {
return !!this.$slots.footer
}
}
}
</script>
<template>
<div>
<div>
<slot />
</div>
<div>
<slot name="footer" />
</div>
<p v-if="hasFooter">I have detected the footer slot!</p>
</div>
</template>
What happens is that the change of the slot content makes the component re-render, and during re-render, $slot.footer
is being evaluated in the template.
You can use a simple function instead of a computed if you don't want to rely on $slots
in the template:
<template>
<div>
<div>
<slot />
</div>
<div>
<slot name="footer" />
</div>
<p v-if="hasFooter()">I have detected the footer slot!</p>
</div>
</template>
<script>
import { computed } from 'vue'
export default {
setup(_, { slots }) {
const hasFooter = () => !!slots.footer
return { hasFooter }
}
}
</script>