반응형
2장: Props - 컴포넌트에 생명 불어넣기
Props는 부모 컴포넌트에서 자식 컴포넌트로 데이터를 전달하는 통로입니다. Props를 통해 재사용 가능한 동적인 컴포넌트를 만드는 방법을 배웁니다.
1. 핵심 개념
Props (Properties): 부모 컴포넌트가 자식 컴포넌트에게 전달하는 데이터 묶음입니다. 자식 컴포넌트는
defineProps매크로를 사용하여 수신할 props를 명시적으로 선언해야 합니다.단방향 데이터 흐름 (One-Way Data Flow): 모든 props는 부모와 자식 사이에 하향식 바인딩을 형성합니다. 부모 속성이 업데이트되면 자식으로 전달되지만, 자식 컴포넌트 내에서 props를 직접 변경해서는 안 됩니다. 이는 데이터 흐름을 예측 가능하게 만듭니다.
Props 선언:
<script setup>내에서defineProps를 사용하여 props를 선언합니다. 배열이나 객체 형태로 타입을 지정할 수 있습니다.defineProps(['name', 'age'])defineProps({ name: String, age: Number })
Props 유효성 검사: 객체 형태의 선언을 사용하면 타입, 필수 여부, 기본값 등 더 상세한 유효성 검사를 지정할 수 있습니다.
2. 예제 코드
예제 1: Props로 다양한 데이터 전달하기
문자열 뿐만 아니라 숫자, 배열, 객체 등 모든 JavaScript 값을 props로 전달할 수 있습니다.
<!-- src/components/UserProfile.vue -->
<script setup>
// defineProps로 수신할 props와 타입을 선언합니다.
const props = defineProps({
name: String,
age: Number,
hobbies: Array
});
</script>
<template>
<div class="profile-card">
<h2>{{ name }}</h2>
<p>나이: {{ age }}세</p>
<h4>취미:</h4>
<ul>
<!-- hobbies 배열을 순회하며 li 태그 생성 -->
<li v-for="hobby in hobbies" :key="hobby">{{ hobby }}</li>
</ul>
</div>
</template>
<style scoped>
.profile-card {
border: 1px solid #ccc;
margin: 10px;
padding: 10px;
}
</style>
<!-- src/App.vue -->
<script setup>
import UserProfile from './components/UserProfile.vue';
import { reactive } from 'vue';
const user1 = reactive({
name: '최동진',
age: 30,
hobbies: ['코딩', '독서', '영화감상']
});
</script>
<template>
<div>
<h1>사용자 프로필</h1>
<!-- v-bind 또는 단축 문법 ':'를 사용하여 props를 전달합니다. -->
<UserProfile
:name="user1.name"
:age="user1.age"
:hobbies="user1.hobbies"
/>
<UserProfile
name="Gemini"
:age="1"
:hobbies="['데이터 분석', '언어 모델링']"
/>
</div>
</template>
예제 2: <slot>으로 컨텐츠 전달하기
React의 children prop과 유사하게, Vue는 <slot> 엘리먼트를 사용하여 부모로부터 컨텐츠를 전달받습니다. 이는 재사용 가능한 레이아웃 컴포넌트를 만들 때 매우 유용합니다.
<!-- src/components/Card.vue -->
<template>
<div class="card">
<!-- 부모 컴포넌트가 Card 태그 사이에 넣은 컨텐츠가 여기에 렌더링됩니다. -->
<slot></slot>
</div>
</template>
<style scoped>
.card {
padding: 20px;
margin: 20px;
box-shadow: 0 4px 8px 0 rgba(0,0,0,0.2);
border-radius: 10px;
background-color: white;
}
</style>
<!-- src/App.vue -->
<script setup>
import Card from './components/Card.vue';
import UserProfile from './components/UserProfile.vue';
</script>
<template>
<div>
<Card>
<!-- 이 부분이 Card 컴포넌트의 <slot>으로 전달됩니다. -->
<h2>첫 번째 카드</h2>
<p>Card 컴포넌트는 다른 컴포넌트나 엘리먼트를 감쌀 수 있습니다.</p>
</Card>
<Card>
<UserProfile
name="최동진"
:age="30"
:hobbies="['코딩', '독서']"
/>
</Card>
</div>
</template>
3. 연습 문제
문제 1: Article 컴포넌트 만들기
- 요구사항: 블로그 게시글을 표시하는
Article.vue컴포넌트를 만드세요. - 세부사항:
title(제목),author(작성자),content(내용)를 props로 받도록defineProps를 설정합니다.<h2>로 제목을,<h4>로 "작성자: [author]"를,<p>로 내용을 표시합니다.
- 도전과제:
App.vue에서Article컴포넌트를 사용하여 2개 이상의 다른 게시글을 렌더링해보세요.
문제 1 정답 예시
<!-- src/components/Article.vue -->
<script setup>
defineProps({
title: String,
author: String,
content: String
});
</script>
<template>
<article>
<h2>{{ title }}</h2>
<h4>작성자: {{ author }}</h4>
<p>{{ content }}</p>
</article>
</template>
<!-- src/App.vue -->
<script setup>
import Article from './components/Article.vue';
</script>
<template>
<div>
<h1>My Blog</h1>
<Article
title="Vue Props 완전 정복"
author="최동진"
content="Props는 컴포넌트 간 데이터 전달의 핵심입니다..."
/>
<hr />
<Article
title="컴포넌트 재사용성 높이기"
author="Gemini"
content="Props를 활용하면 컴포넌트를 다양한 상황에서 재사용할 수 있습니다."
/>
</div>
</template>
문제 2: ImageCard 컴포넌트 만들기
- 요구사항: 이미지와 설명을 함께 보여주는
ImageCard.vue컴포넌트를 만드세요. - 세부사항:
imageUrl(이미지 주소)과caption(설명)을 props로 받도록defineProps를 설정합니다.<img>태그로 이미지를 표시하고, 그 아래<p>태그로 설명을 표시합니다.
- 도전과제:
App.vue에서ImageCard컴포넌트를 사용하여 좋아하는 이미지 2개 이상을 화면에 띄워보세요. (이미지 주소는 인터넷에서 검색하여 사용할 수 있습니다.)
문제 2 정답 예시
<!-- src/components/ImageCard.vue -->
<script setup>
defineProps({
imageUrl: {
type: String,
required: true
},
caption: {
type: String,
default: '이미지 설명이 없습니다.'
}
});
</script>
<template>
<figure>
<img :src="imageUrl" :alt="caption" width="300" />
<figcaption>{{ caption }}</figcaption>
</figure>
</template>
<!-- src/App.vue -->
<script setup>
import ImageCard from './components/ImageCard.vue';
</script>
<template>
<div>
<h1>Image Gallery</h1>
<ImageCard
image-url="https://via.placeholder.com/300x200.png?text=Vue"
caption="Vue 로고"
/>
<ImageCard
image-url="https://via.placeholder.com/300x200.png?text=JavaScript"
caption="JavaScript 로고"
/>
</div>
</template>
반응형
'프론트엔드 > 뷰' 카테고리의 다른 글
| [Vue] 9장: 스타일링 - 컴포넌트에 옷 입히기 (0) | 2025.09.23 |
|---|---|
| [Vue] 8장: 컴포저블과 반응성 심화 - Vue 능력 끌어올리기 (0) | 2025.09.23 |
| [Vue] 7장: 폼과 `v-model` - 사용자의 입력 받기 (0) | 2025.09.23 |
| [Vue] 6장: 리스트 렌더링 - 동적인 목록 만들기 (0) | 2025.09.23 |
| [Vue] 5장: 조건부 렌더링 - 상황에 맞는 UI 보여주기 (0) | 2025.09.23 |
| [Vue] 4장: 이벤트 핸들링 - 사용자와의 상호작용 (0) | 2025.09.23 |
| [Vue] 3장: 반응성과 생명주기 - 살아 움직이는 컴포넌트 (0) | 2025.09.23 |
| [Vue] 1장: 템플릿과 컴포넌트 - Vue.js의 첫인상 (0) | 2025.09.23 |