본문으로 건너뛰기
개발 머꼬
개발 노트Vue
hohyeon.dev19

슬롯 안에서 자식의 v-for 변수를 못 쓴 이유

  • #Engineering Note
  • #Vue

문제 발생

목록 컴포넌트를 재사용하려고 만들었는데, 슬롯 안에서 자식이 가진 항목 데이터를 쓸 수 없었습니다.

<!-- 부모 -->
<ItemList :items="items">
  <span>{{ item.name }}</span>   <!-- item is not defined -->
</ItemList>

itemItemList 안의 v-for 변수라 부모에서는 존재하지 않았습니다.

원인 분석

렌더 스코프 규칙입니다. 공식 문서가 명확히 적습니다 — 부모 템플릿의 표현식은 부모 스코프에만, 자식 템플릿의 표현식은 자식 스코프에만 접근할 수 있습니다. 자바스크립트의 렉시컬 스코프와 같습니다.

슬롯에 넣은 내용은 부모가 작성한 템플릿입니다. 자식 컴포넌트 안에 그려질 뿐, 자식의 변수를 볼 권한은 없습니다.

자식이 가진 값을 슬롯 내용이 쓰게 하려면 자식이 넘겨줘야 합니다. 그게 스코프드 슬롯입니다 — <slot>에 prop을 붙이면 부모가 v-slot으로 받습니다.

해결 방안

  1. 자식이 슬롯 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>
  1. 이름 있는 슬롯도 같은 방식입니다. #이름="props" 형태로 받습니다.
<!-- 자식 -->
<slot name="header" message="hello" />

<!-- 부모 -->
<MyComponent>
  <template #header="headerProps">{{ headerProps.message }}</template>
</MyComponent>
  1. 기본값을 둡니다. <slot> 안에 넣은 내용은 부모가 아무것도 주지 않았을 때만 그려집니다.
<button type="submit">
  <slot>저장</slot>
</button>
  1. 슬롯이 비었으면 껍데기도 지웁니다. $slots로 확인해서 래퍼 요소 자체를 조건부로 그립니다 — 안 그러면 빈 테두리와 여백만 남습니다.
<div class="card">
  <div v-if="$slots.header" class="card-header"><slot name="header" /></div>
  <div class="card-body"><slot /></div>
</div>
  1. v-slot<template>이나 컴포넌트 태그에만 씁니다. 슬롯이 하나뿐이면 컴포넌트 태그에 바로 붙일 수 있고, 여러 개면 각각 <template #이름>으로 나눕니다.

  2. 스코프드 슬롯은 "로직은 내가, 겉모습은 네가"의 도구입니다. 목록·테이블·무한 스크롤처럼 동작은 같고 표현만 다른 컴포넌트에서 특히 유용합니다. 자식은 데이터 로딩과 반복을 책임지고, 부모는 한 행을 어떻게 그릴지만 정합니다.

공식 문서

마지막 수정

좋아요북마크

댓글0

아직 댓글이 없어요. 첫 의견을 편하게 남겨 보세요.