The Problem

When you pass content through Vue slots, the slot content is compiled in the parent's scope. If the parent's reactive state changes, the slot content may not re-render because the reactivity context was lost during the slot projection.

Symptoms

  • Parent state changes but slot content still shows old values
  • Works with direct template binding but not through slots
  • Scoped slots work but regular slots do not update
  • Child component re-renders but slot content is stale

Real Error Scenario

```vue <!-- Parent.vue --> <template> <CardWrapper> <p>Count: {{ count }}</p> <!-- Does NOT update when count changes --> </CardWrapper> </template>

<script setup> const count = ref(0); setInterval(() => count.value++, 1000); </script>

<!-- CardWrapper.vue --> <template> <div class="card"> <slot></slot> <!-- Slot content is compiled once --> </div> </template> ```

Actually, in Vue 3, default slots DO re-render because the parent re-renders and the slot content is part of the parent's VNode tree. The issue typically arises with more complex scenarios.

Real Scenario: Reactivity Loss Through Dynamic Components

```vue <!-- Parent --> <template> <DynamicWrapper :component="currentComponent"> <template #header> <h1>{{ title }}</h1> <!-- May not update if wrapper caches --> </template> </DynamicWrapper> </template>

<script setup> const title = ref('Initial'); const currentComponent = shallowRef(ComponentA);

// Later: title.value = 'Updated'; // Slot may not re-render if wrapper cached its slots </script> ```

How to Fix It

Fix 1: Use Scoped Slots for Reactive Data

```vue <!-- CardWrapper.vue --> <template> <div class="card"> <slot :count="count" :title="title"></slot> </div> </template>

<script setup> const count = ref(0); const title = ref('Card Title'); </script>

<!-- Parent.vue --> <CardWrapper v-slot="{ count, title }"> <p>{{ title }}: {{ count }}</p> </CardWrapper> ```

Fix 2: Pass Reactive Data as Props Instead

vue
<!-- Instead of slotting reactive content, pass it as props -->
<CardWrapper :title="title" :count="count">
  <p>Static content here</p>
</CardWrapper>

Fix 3: Force Re-render with Key

vue
<CardWrapper :key="title + count">
  <p>{{ title }}: {{ count }}</p>
</CardWrapper>

Fix 4: Avoid Caching Slots

```vue <!-- WRONG: v-once prevents re-renders --> <CardWrapper> <p v-once>{{ title }}</p> </CardWrapper>

<!-- WRONG: Shallow ref does not deep-track changes --> const config = shallowRef({ title: 'Hello' }); ```