Vue는 컴포넌트 기반 구조이기 때문에 각 컴포넌트는 독립적인 유효 범위(scope) 를 갖습니다.
즉, 부모와 자식 컴포넌트 간에도 데이터를 직접 접근할 수 없고, Vue의 규칙적인 통신 방식을 통해서만 전달해야 합니다.
prop을 읽기 전용으로 사용1// 자식 컴포넌트 정의
2Vue.component('blog-post', {
3 props: ['title'],
4 template: '<h3>{{ title }}</h3>'
5})
6
7// 부모 컴포넌트 템플릿
8<blog-post :title="hello"></blog-post>
9
10자식이 prop을 직접 변경하면 데이터 흐름이 복잡해지고, 디버깅이 어려워짐
Vue에서 권장하는 방법은 다음과 같습니다:
1props: ['initialCounter'],
2data() {
3 return {
4 counter: this.initialCounter
5 }
6}이 방법은 초기값만 prop으로 받고, 이후엔 자식 컴포넌트 내부에서 관리하는 형태
1props: ['size'],
2computed: {
3 normalizedSize() {
4 return this.size.trim().toLowerCase()
5 }
6}원본 데이터를 변경하지 않고, 가공된 데이터를 사용해야 할 때 유용
1// 자식 컴포넌트
2<template>
3 <button @click="$emit('update:title', 'new title')">Change Title</button>
4</template>
5
6// 부모 컴포넌트
7<blog-post :title="title" @update:title="title = $event"></blog-post>
8이 방식은 Vue 3의 v-model 커스텀 바인딩 패턴과 연결됩니다 (아래에서 자세히 설명)
v-model은 사용자 입력과 Vue 인스턴스의 데이터를 자동으로 동기화하는 디렉티브입니다.
<input v-model="inputText" />new Vue({
data: {
inputText: ''
}
})사용자가 input에 타이핑하면 inputText가 자동으로 업데이트됨
<input:value="inputText"
@input="inputText = $event.target.value"
/>
즉, v-model = v-bind:value + v-on:input
| 입력 요소 | 바인딩 대상 | 이벤트 |
|---|---|---|
<input> | value | input |
<checkbox> | checked | change |
<select> | value | change |
| 수식어 | 설명 |
|---|---|
.lazy | change 이벤트 이후 동기화 (기본은 input 이벤트) |
.number | 입력값을 자동으로 숫자로 형변환 |
.trim | 입력값의 앞뒤 공백 제거 |
<input v-model.lazy="msg">
<input v-model.number="age" type="number">
<input v-model.trim="comment">v-model 대신 아래와 같이 직접 바인딩하는 것이 더 안정적임<input:value="inputText"
@input="inputText = $event.target.value"
/>
v-model로 DOM ↔ 데이터 연결v-on으로 사용자 이벤트 처리Vue 3에서는 v-model로 바인딩할 prop 이름을 커스터마이징 가능
1<!-- 부모 컴포넌트 -->
2<custom-input v-model:title="bookTitle" />
3
4<!-- 자식 컴포넌트 -->
5props: ['title'],
6emits: ['update:title']이 방식은 복잡한 컴포넌트 구조에서도 양방향 데이터 바인딩을 안전하게 유지할 수 있게 해줍니다.
| 항목 | 요약 |
|---|---|
props | 부모 → 자식 데이터 전달 (단방향, 읽기 전용) |
v-model | 사용자 입력과 데이터 동기화 (양방향 바인딩) |
양방향 바인딩 | Vue에서는 v-model, v-on 등으로 구현됨 |
주의사항 | IME 입력 이슈, 객체 참조 주의, prop 직접 수정 금지 |