컴포넌트 A와 컴포넌트 B가 있다고 가정할 때, 서로 의사 소통을 필요로 한다면
부모는 자식에게 데이터를 전달할 수 있어야 하고, 자식은 자신에게 일어난 일을 부모에게 알릴 수 있어야 한다.
Vue.js에서 부모-자식 컴포넌트 관계는
props
는 아래로(부모에서 자식),events
는 위로(자식에서 부모로) 라고 요약할 수 있다.
부모는 props
를 통해 자식에게 데이터를 전달하고,
자식은 events
를 통해 부모에게 메세지를 보낸다.
모든 컴포넌트 인스턴스에는 자체 격리 된 범위가 있어 하위 컴포넌트의 템플릿에서 상위 데이터를 직접 참조할 수 없다.
부모 컴포넌트는 props
옵션을 사용하여 데이터를 하위 컴포넌트로 전달할 수 있다.
하위 컴포넌트는 props
옵션을 사용하여 수신할 것으로 기대되는 props
를 명시적으로 선언해야 한다.
<!-- 부모 컴포넌트 -->
<!-- HTML 속성은 대소문자를 구분하지 않으므로 kebab-case 사용 -->
<child from-parent="hello!"></child>
// 자식 컴포넌트
Vue.component('child', {
props: ['fromParent'], // JavaScript에서는 camelCase 사용
template: '<h3>{{ fromParent }}</h3>'
})
<!-- 결과 화면 -->
<h3>hello!</h3>
props
정규 속성을 표현식에 바인딩 하는 것과 비슷하게,
v-bind
를 사용하여 부모의 데이터에 props
를 동적으로 바인딩할 수 있다.
데이터가 상위에서 업데이트 될 때마다 하위 데이터에게도 전달된다.
<!-- 부모 컴포넌트 -->
<div>
<input v-model="inputMsg">
<child v-bind:fromParent="inputMsg"></child>
</div>
객체의 모든 속성을 props
로 전달하려면, 인자 없이 v-bind
를 쓸 수 있다.
(v-bind:prop명
대신 v-bind
)
// 부모 컴포넌트
parentObject: {
test: 'Learn Vue',
isComplete: false
}
<!-- 부모 컴포넌트 -->
<todo-item v-bind="parentObject"></todo-item>
<!-- ↑ 같은 거 ↓ -->
<todo-item
v-bind:text="parentObject.text"
v-bind:is-complete="parentObject.isComplete"
></todo-item>
// 자식 컴포넌트
Vue.component('child', {
props: ['text', 'isComplete'], // JavaScript에서는 camelCase 사용
template: '<h3>{{ text }} {{ isComplete }}</h3>'
})
흔히 하는 실수는 리터럴 구문을 사용하여 숫자를 전달하려고 시도하는 것이다.
리터럴 prop
이기 때문에 그 값은 실제 숫자가 아닌 일반 문자열 "1"로 전달된다.
<!-- 일반 문자열 "1"을 전달 -->
<comp some-prop="1"></comp>
<!-- 숫자를 전달하려면 값이 JavaScript 표현식으로 평가되도록 `v-bind`를 사용 -->
<comp v-bind:some-prop="1"></comp>
<!-- 값이 없는 prop은 'true'를 전달 -->
<comp prop-bool></comp>
<!-- JavaScript 표현식 'false'로 값을 전달하려면 `v-bind`를 사용 -->
<comp v-bind:prop-bool="false"></comp>
<!-- 변수의 값을 동적으로 할당 -->
<comp v-bind:prop-bool="bool.propBool"></comp>
모든 props
는 상위 속성과 하위 속성 사이의 단방향 바인딩을 형성한다.
상위 속성이 업데이트되면 하위로 흐르게 되지만, 그 반대는 안 된다.
props
로 받은 데이터를 변경하고 싶을 경우, 아래 예시에 따른다.
props
는 초기값을 전달하기 위해 사용되며,
하위 컴포넌트는 props
를 로컬 데이터 속성으로 사용할 때
이 경우 props
를 data
에 정의하는 것이 가장 좋다.
props: ['initialCounter'],
data: function () {
return { counter: this.initialCounter }
}
props
가 변환이 필요한 원시 값으로 전달 될 때
이 경우 props
를 computed
에 정의하는 것이 가장 좋다.
props: ['size'],
computed: {
normalizedSize: function () {
return this.size.trim().toLowerCase()
}
}
++ JavaScript의 객체와 배열은 참조로 전달되므로 props
가 배열이나 객체인 경우,
하위 객체 또는 배열 자체를 부모 상태로 변경하면 부모 상태에 영향을 준다.
props
검증컴포넌트가 받는 중인 prop
에 대한 요구사항(type, default, validation)을 지정할 수 있다.
지정한 요구사항이 충족 되지 않으면 Vue에서 경고를 보낸다.
이 기능은 다른 사용자가 사용할 컴포넌트를 제작할 때 유용하며,
props
를 문자열 배열로 정의(ex. props: ['text'])는 대신 유효성 검사 요구사항이 있는 객체를 사용할 수 있다.
String
, Number
, Boolean
, Array
, Object
, Date
, Function
Symbol
Vue.component('my-component', {
props: {
// 기본 타입 확인
propA: Number,
propA_1: null, // `null`과 `undefined`는
propA_2: undefined, // 어떤 타입이든 가능하다 라는 뜻
// 여러 개 타입이 가능 (아래의 경우 String, Number만 가능)
propB: [String, Number],
// 문자열이며 꼭 필요로 함
propC: {
type: String,
required: true
},
// 숫자이며 기본 값(100)을 가짐
propD: {
type: Number,
default: 100
},
//
propE: {
type: Object,
// 객체∙배열의 기본값은 팩토리 함수에서 반환되어야 함
default: function () {
return { message: 'hello' }
}
},
// 사용자 정의 유효성 검사
propF: {
validator: function (value) {
return ['success', 'warning', 'danger'].includes(value)
}
}
}
})
props
는 컴포넌트 인스턴스가 생성되기 전에 검증된다.
때문에 default, validator 함수 내에서 data, computed, methods 같은 인스턴스 속성을 사용할 수 없다.
function Person (firstName, lastName) {
this.firstName = firstName
this.lastName = lastName
}
Vue.component('book-post',{
props: {
author: Person
}
})