컴포넌트 등록, props 전달, emit으로 이벤트 올려보내기.
컴포넌트 — props 와 emit
앱이 커지면 화면 전체를 한 파일에 담을 수 없습니다. 버튼, 카드, 목록 같은 조각을 컴포넌트로 나누고 조립하죠. 이때 부모는 자식에게 데이터를 props 로 내려주고, 자식은 부모에게 사건을 emit 으로 올려보냅니다. 이 단방향 흐름이 Vue 컴포넌트 통신의 기본입니다.
학습 목표
- 자식 컴포넌트를 import 해서 사용한다.
defineProps로 부모에게서 데이터를 받는다.defineEmits로 부모에게 이벤트를 올려보낸다.- 단방향 데이터 흐름의 원칙과 props 검증을 이해한다.
컴포넌트 등록과 사용
<script setup> 에서는 자식 컴포넌트를 import 만 하면 바로 template 에서 쓸 수 있습니다. 별도 등록 코드가 필요 없습니다.
<!-- Parent.vue -->
<script setup>
import UserCard from './UserCard.vue';
</script>
<template>
<UserCard name="민수" :age="20" />
</template>
props 받기 — defineProps
자식은 defineProps 로 받을 데이터를 선언합니다. defineProps 는 import 없이 쓸 수 있는 컴파일러 매크로입니다.
<!-- UserCard.vue -->
<script setup>
const props = defineProps({
name: String,
age: Number,
});
console.log(props.name); // script 에서 접근
</script>
<template>
<div class="card">
<h3>{{ name }}</h3> <!-- template 에선 바로 -->
<p>{{ age }}살</p>
</div>
</template>
💡 TIP — 부모에서
name="민수"처럼 문자열을 그냥 넘기면 문자열로, 숫자·불리언·배열·객체는:age="20"처럼v-bind(:)를 붙여 넘겨야 실제 타입으로 전달됩니다.
단방향 데이터 흐름
데이터는 항상 부모 → 자식 한 방향으로 흐릅니다. 자식이 받은 props를 직접 바꾸면 안 됩니다.
// X 금지 — props 는 읽기 전용
props.age = 30;
값을 바꿔야 한다면 이벤트로 부모에게 요청하고, 부모가 원본을 바꿔서 다시 내려보냅니다.
emit — 부모에게 이벤트 올리기
자식은 defineEmits 로 발생시킬 이벤트를 선언하고, 호출해서 부모에게 알립니다.
<!-- UserCard.vue -->
<script setup>
defineProps({ name: String });
const emit = defineEmits(['select', 'delete']);
</script>
<template>
<div class="card">
<h3>{{ name }}</h3>
<button @click="emit('select', name)">선택</button>
<button @click="emit('delete')">삭제</button>
</div>
</template>
부모는 @이벤트명 으로 받습니다.
<!-- Parent.vue -->
<template>
<UserCard
name="민수"
@select="onSelect"
@delete="onDelete"
/>
</template>
emit('select', name) 의 두 번째 인자는 부모 핸들러 onSelect(payload) 의 인자로 전달됩니다.
props 검증
타입뿐 아니라 필수 여부·기본값·커스텀 검증을 줄 수 있습니다.
const props = defineProps({
title: { type: String, required: true },
count: { type: Number, default: 0 },
status: {
type: String,
validator: (v) => ['ok', 'warn', 'error'].includes(v),
},
});
⚠️ 주의 — 객체·배열의
default는 함수로 반환해야 합니다:default: () => []. 그렇지 않으면 모든 인스턴스가 같은 참조를 공유해 버그가 생깁니다.
요약
<script setup>에선 자식 컴포넌트를 import 만 하면 쓸 수 있다.defineProps로 부모 데이터를 받고, 객체/숫자 등은:로 넘긴다.- props는 읽기 전용이며 데이터는 부모→자식 단방향으로 흐른다.
defineEmits로 이벤트를 선언·발생시켜 부모에게 알린다.
연습문제
name,price를 props로 받아 표시하는ProductItem.vue를 만들어 보세요.- 1번 컴포넌트에 "담기" 버튼을 두고, 클릭 시
add이벤트로 상품 이름을 부모에게 emit 해 보세요. priceprops에required: true와 타입 검증을 추가해 보세요.- 자식이 props를 직접 수정하면 왜 안 되는지, 대신 어떻게 해야 하는지 설명해 보세요.
힌트 —
defineEmits(['add'])후emit('add', name). 부모에서@add="cart.push($event)"처럼 받을 수 있습니다.
💡 연습문제 풀이
불러오는 중…
댓글 0
“Vue.js” 강좌에 대한 댓글입니다.