슬롯 안에서 자식의 v-for 변수를 못 쓴 이유
문제 발생
목록 컴포넌트를 재사용하려고 만들었는데, 슬롯 안에서 자식이 가진 항목 데이터를 쓸 수 없었습니다.
<!-- 부모 -->
<ItemList :items="items">
<span>{{ item.name }}</span> <!-- item is not defined -->
</ItemList>item은 ItemList 안의 v-for 변수라 부모에서는 존재하지 않았습니다.
원인 분석
렌더 스코프 규칙입니다. 공식 문서가 명확히 적습니다 — 부모 템플릿의 표현식은 부모 스코프에만, 자식 템플릿의 표현식은 자식 스코프에만 접근할 수 있습니다. 자바스크립트의 렉시컬 스코프와 같습니다.
슬롯에 넣은 내용은 부모가 작성한 템플릿입니다. 자식 컴포넌트 안에 그려질 뿐, 자식의 변수를 볼 권한은 없습니다.
자식이 가진 값을 슬롯 내용이 쓰게 하려면 자식이 넘겨줘야 합니다. 그게 스코프드 슬롯입니다 — <slot>에 prop을 붙이면 부모가 v-slot으로 받습니다.
해결 방안
- 자식이 슬롯 prop으로 넘깁니다.
<!-- ItemList.vue -->
<template>
<ul>
<li v-for="item in items" :key="item.id">
<slot :item="item" :index="items.indexOf(item)" />
</li>
</ul>
</template><!-- 부모 -->
<ItemList :items="items" v-slot="{ item }">
<span>{{ item.name }}</span>
</ItemList>- 이름 있는 슬롯도 같은 방식입니다.
#이름="props"형태로 받습니다.
<!-- 자식 -->
<slot name="header" message="hello" />
<!-- 부모 -->
<MyComponent>
<template #header="headerProps">{{ headerProps.message }}</template>
</MyComponent>- 기본값을 둡니다.
<slot>안에 넣은 내용은 부모가 아무것도 주지 않았을 때만 그려집니다.
<button type="submit">
<slot>저장</slot>
</button>- 슬롯이 비었으면 껍데기도 지웁니다.
$slots로 확인해서 래퍼 요소 자체를 조건부로 그립니다 — 안 그러면 빈 테두리와 여백만 남습니다.
<div class="card">
<div v-if="$slots.header" class="card-header"><slot name="header" /></div>
<div class="card-body"><slot /></div>
</div>-
v-slot은<template>이나 컴포넌트 태그에만 씁니다. 슬롯이 하나뿐이면 컴포넌트 태그에 바로 붙일 수 있고, 여러 개면 각각<template #이름>으로 나눕니다. -
스코프드 슬롯은 "로직은 내가, 겉모습은 네가"의 도구입니다. 목록·테이블·무한 스크롤처럼 동작은 같고 표현만 다른 컴포넌트에서 특히 유용합니다. 자식은 데이터 로딩과 반복을 책임지고, 부모는 한 행을 어떻게 그릴지만 정합니다.
댓글0
댓글을 남기려면 로그인이 필요해요. 로그인
아직 댓글이 없어요. 첫 의견을 편하게 남겨 보세요.