컴포넌트 간 데이터 전달 방식
Vue.js에서 컴포넌트 간의 데이터 교환은 애플리케이션 설계의 핵심 요소입니다. 다양한 통신 패턴을 통해 부모-자식 컴포넌트 및 형제 컴포넌트 간의 효율적인 데이터 흐름을 구현할 수 있습니다.
1. Props를 통한 단방향 데이터 흐름
부모 컴포넌트에서 자식 컴포넌트로 데이터를 전달하는 기본적인 방법입니다. 함수 타입의 props는 자식에서 부모로의 이벤트 발생에 활용됩니다.
// props 정의 방식
{
items: Array,
config: {
type: Object,
default: () => ({})
}
}
2. 사용자 정의 이벤트
자식 컴포넌트에서 부모 컴포넌트로 데이터를 전달할 때 사용합니다. $emit과 $on 메서드를 활용하여 이벤트 기반 통신을 구현합니다.
3. 전역 이벤트 버스
모든 컴포넌트 간의 자유로운 통신이 필요한 경우 활용됩니다.
Vue.prototype.$eventHub = new Vue();
4. PubSub 패턴
React 생태계에서도 널리 사용되는 발행-구독 패턴으로, 프레임워크에 관계없이 범용적으로 적용 가능한 통신 방식입니다.
5. Vuex 상태 관리
복잡한 애플리케이션의 상태를 중앙 집중식으로 관리하여 모든 컴포넌트에서 접근 가능하도록 합니다.
6. 슬롯(Slots)
컴포넌트 간의 구조적 통신을 위한 방법으로 다음과 같은 유형이 있습니다:
- 기본 슬롯
- 이름이 지정된 슬롯
- 범위 슬롯
v-model 심화 이해
v-model 디렉티브는 폼 요소와 함께 사용되어 양방향 데이터 바인딩을 구현합니다. 내부적으로는 value 속성과 input 이벤트의 조합으로 동작합니다.
<template>
<div>
<input
:value="message"
@input="handleInput">
<p>{{ message }}</p>
</div>
</template>
<script>
export default {
data() {
return {
message: ''
}
},
methods: {
handleInput(event) {
this.message = event.target.value
}
}
}
</script>
컴포넌트에서의 v-model 활용
폼 요소 외에도 컴포넌트에서 v-model을 사용하여 부모-자식 간 양방향 바인딩을 구현할 수 있습니다.
// 부모 컴포넌트
<template>
<div>
<custom-input v-model="status"></custom-input>
<div>상태: {{ status }}</div>
</div>
</template>
// 자식 컴포넌트
<template>
<div>
<button @click="toggleStatus">토글</button>
</div>
</template>
<script>
export default {
props: {
value: Boolean
},
methods: {
toggleStatus() {
this.$emit('input', !this.value)
}
}
}
</script>
model 옵션을 통한 커스터마이징
기본적인 value/input 패턴 대신 커스텀 프로퍼티와 이벤트 이름을 지정할 수 있습니다.
export default {
model: {
prop: 'checked',
event: 'change'
},
props: {
checked: Boolean
}
}
.sync 수식어
부모-자식 컴포넌트 간의 양방향 데이터 동기화를 위한 간편한 문법입니다.
<child-component :amount.sync="balance"></child-component>
$attrs와 $listeners
하위 컴포넌트로 전달되는 모든 속성과 이벤트 리스너에 접근할 수 있는 특수 속성입니다.
{
// props로 받지 않은 속성들
$attrs: { title: 'example' },
// 상속된 이벤트 리스너들
$listeners: { customEvent: handler }
}
$children와 $parent
직계 부모 또는 자식 컴포넌트 인스턴스에 직접 접근할 수 있는 참조 속성입니다.
Mixins
여러 컴포넌트에서 공통으로 사용되는 로직을 재사용 가능한 단위로 추출할 수 있습니다.
const commonMixin = {
data() {
return {
sharedData: 'common'
}
},
methods: {
sharedMethod() {
console.log('공유 메서드')
}
}
}
export default {
mixins: [commonMixin]
}
Scoped Slots
데이터를 제공하는 컴포넌트가 구조를 결정하지 않고, 데이터 소비 컴포넌트가 렌더링 구조를 제어할 수 있도록 합니다.
데이터 초기화 유틸리티
// 컴포넌트 데이터를 초기 상태로 되돌리는 방법
Object.assign(this._data, this.$options.data())
CSS Scoped와 Deep Selector
<style scoped>를 사용하면 컴포넌트 스타일의 범위를 제한할 수 있으며, 하위 컴포넌트 스타일까지 영향을 주려면 깊이 선택자를 사용합니다.
/* 일반 CSS */
.parent >>> .child { }
/* Less */
.parent /deep/ .child { }
/* SCSS */
.parent ::v-deep .child { }