Props와 Emit만으로 모든 것을 해결하려다 보면 문제가 생깁니다. 부모가 자식의 내부 디자인(HTML)을 통째로 갈아 끼우고 싶거나, 할아버지 컴포넌트가 저 아래 까마득한 손자 컴포넌트에게 데이터를 주고 싶을 때는 어떻게 할까요? 이때 Slots와 Provide/Inject가 등장합니다.
<script setup>
import { provide, ref } from 'vue';
import Modal from './Modal.vue';
import GrandChild from './GrandChild.vue';
// [1. Provide] 할아버지가 데이터를 제공합니다.
// 이 데이터는 자식, 손자, 증손자 등 하위 컴포넌트 어디서든 바로 꺼내 쓸 수 있습니다.
const themeColor = ref('dark');
provide('theme', themeColor);
const closeModal = () => alert("닫기 버튼 클릭됨!");
</script>
<template>
<div class="p-8 bg-slate-800 max-w-lg mx-auto rounded-lg">
<h2>1. Provide / Inject</h2>
<!-- 손자 컴포넌트를 그냥 불러옵니다. Props를 안 넘겨줘도 됩니다! -->
<GrandChild />
<h2>2. Named Slots (이름 있는 슬롯)</h2>
<!-- [2. Slots] 자식 컴포넌트의 구멍(slot)에 HTML 끼워넣기 -->
<Modal>
<!-- 자식 컴포넌트의 <slot name="header"> 위치에 들어갈 HTML -->
<template #header>
<h1 class="text-2xl text-red-500 font-bold">경고: 결제 실패</h1>
</template>
<!-- 자식 컴포넌트의 기본 <slot> 위치에 들어갈 HTML -->
<p class="text-slate-300 my-4">잔액이 부족하여 결제가 취소되었습니다.</p>
<!-- 자식 컴포넌트의 <slot name="footer"> 위치에 들어갈 HTML -->
<template #footer>
<button class="bg-blue-600 text-white px-4 py-2 rounded" @click="closeModal">확인 및 닫기</button>
</template>
</Modal>
</div>
</template>