2025. 3. 30. 15:49ㆍFront-End/Vue.js
컴포넌트를 사용하다 보면 화면 구조는 동일하지만 표시되는 데이터만 다르게 처리하고 싶을 때가 많다. 예를 들어 블로그 게시글을 나타내는 PostItem 컴포넌트를 만들고, 게시글의 제목과 내용을 외부에서 받아서 다르게 보여주고 싶을 수 있다.
이런 경우 사용하는 것이 바로 props다.
Props란?
props는 부모 컴포넌트에서 자식 컴포넌트로 데이터를 전달할 수 있도록 하는 사용자 정의 속성이다.
간단히 말하면, 컴포넌트를 재사용하되 그 안에 표시되는 데이터를 동적으로 다르게 주고 싶을 때 사용하는 메커니즘이다.
Props 선언 방법
- 문자열 배열로 선언
// PostItem.vue
export default {
props: ['title'],
setup(props) {
console.log(props.title);
}
}
- 객체 형태로 선언
좀 더 구체적으로 타입이나 기본값, 유효성 검사 등을 추가하고 싶을 때는 객체 형태로 선언한다.
export default {
props: {
title: String,
views: {
type: Number,
default: 0
},
isPublished: {
type: Boolean,
required: true
},
tagList: {
type: Array,
default: () => []
},
status: {
validator(value) {
return ['draft', 'public', 'archived'].includes(value);
}
}
}
}
- type: 기대하는 타입 지정
- required: 필수 여부
- default: 기본값 설정 (객체/배열은 함수로 반환)
- validator: 유효성 검사 함수
Props 사용 방법
1. 템플릿에서 직접 사용
<template>
<article>
<h2>{{ title }}</h2>
<p>{{ content }}</p>
</article>
</template>
2. setup() 함수에서 사용
export default {
props: ['title', 'content'],
setup(props) {
console.log(props.title);
return { ...props };
}
}
Props 이름 규칙
- 컴포넌트 내부에서는 camelCase 사용 (예: postTitle)
- 부모에서 전달할 때는 kebab-case 사용 (예: post-title)
<!-- 부모 컴포넌트 -->
<PostItem post-title="Vue 소개" />
// 자식 컴포넌트
export default {
props: ['postTitle']
}
객체 형태로 여러 props 한 번에 전달
v-bind를 이용해 객체 전체를 props로 전달할 수 있다.
const post = reactive({
title: 'Vue 3 배우기',
content: '컴포넌트와 반응형 시스템을 익혀보세요.'
});
<!-- 아래 두 줄은 동일한 의미 -->
<PostItem v-bind="post" />
<PostItem :title="post.title" :content="post.content" />
단방향 바인딩
Vue의 props는 단방향으로만 전달된다. 부모 → 자식 방향만 가능하며, 자식에서 props를 직접 변경할 수는 없다.
export default {
props: ['count'],
setup(props) {
// ❌ 잘못된 예시 - props는 readonly
props.count = 10;
}
}
자식에서 변경이 필요한 경우
1. props를 로컬 state로 복사
초기값 용도로 사용하고 이후에는 로컬 상태로 관리한다.
export default {
props: ['initialValue'],
setup(props) {
const value = ref(props.initialValue);
return { value };
}
}
2. 변형된 값을 계산해서 사용하는 경우
computed를 활용하면 원본 props는 유지하면서 변형된 값을 만들 수 있다.
export default {
props: ['username'],
setup(props) {
const formatted = computed(() => props.username.trim().toUpperCase());
return { formatted };
}
}
객체/배열 props의 변경
Vue에서는 객체나 배열이 참조 타입이기 때문에 자식 컴포넌트에서 내부 값을 수정할 수는 있지만, 이건 권장되는 방식이 아니다.
export default {
props: ['user'],
setup(props) {
// 가능하지만 추천되지 않음
props.user.name = '홍길동';
}
}
이렇게 하면 데이터 흐름을 추적하기 어려워지고, 유지보수가 힘들어진다. 대신 변경이 필요하다면 emit으로 부모에게 알리는 방식이 좋다.
Boolean props의 캐스팅
불리언 타입의 props는 HTML 상에서 값 없이 사용할 수 있다.
export default {
props: {
disabled: Boolean
}
}
<!-- true로 전달됨 -->
<MyButton disabled />
<!-- false로 전달됨 -->
<MyButton :disabled="false" />
toRef, toRefs로 반응형 유지하며 구조 분해
setup() 함수 안에서 props를 구조분해할 경우 반응형 연결이 끊길 수 있다. 이때는 toRef나 toRefs를 사용한다.
import { toRef, toRefs } from 'vue';
export default {
props: ['message', 'count'],
setup(props) {
const message = toRef(props, 'message');
const { count } = toRefs(props);
return { message, count };
}
}
toRef는 특정 key 하나만 반응형으로 연결하고, toRefs는 전체 props 객체를 반응형으로 유지하면서 구조분해할 수 있도록 해준다.
정리
- props는 부모 → 자식 데이터 전달용
- 타입, 필수 여부, 기본값, 유효성 검사까지 선언 가능
- 객체 전체를 v-bind로 전달할 수 있음
- props는 단방향이며, 자식에서 직접 수정하면 안 됨
- 수정이 필요할 경우 로컬 변수에 복사하거나 emit으로 부모에게 요청
- 구조 분해 시 toRef, toRefs로 반응형 유지
컴포넌트를 유연하게 설계하려면 props를 명확히 선언하고, 그 사용 목적에 따라 읽기 전용 데이터인지, 상태로 전환할 데이터인지 구분해서 쓰는 것이 중요하다.
'Front-End > Vue.js' 카테고리의 다른 글
Vue 3 – Slot을 활용한 컴포넌트 콘텐츠 전달 (0) | 2025.03.30 |
---|---|
Vue 3 - Non-Prop 속성 제대로 이해하기 (0) | 2025.03.30 |
Vue 3 – 이벤트(emit)로 컴포넌트 간 데이터 전달하기 (0) | 2025.03.30 |
<Vue.js> v-directives (0) | 2024.08.19 |
<Vue.js> 컴포넌트 (0) | 2024.08.19 |