vue.js - 컴포넌트 - Props
컴포넌트 관계
- 컴포넌트는 부모-자식 관계에서 가장 일반적으로 사용하기 위한 것입니다.
- 여기서 부모와 자식 컴포넌트는 서로에게 데이터를 전달하거나, 이벤트를 알릴 필요가 있습니다.
- Vue에서 부모-자식 컴포넌트 관계는 props(아래)와 events(위로)라고 얘기할 수 있습니다.
- 부모는 props를 통해 자식에게 데이터를 전달하고, 자식은 events를 이용해 부모에게 메시지를 전달합니다.
Props
- 모든 컴포넌트 인스턴스는 자체 범위가 있어, 하위 컴포넌트의 템플릿에서 상위 데이터를 직접 참조할 수 없습니다.
- 데이터는 props옵션을 사용해서만 하위 컴포넌트로 전달 될 수 있습니다.
<child message="안녕하세요!"></child>
<script>
Vue.component('child', {
// props 정의
props: ['message'],
// 데이터와 마찬가지로 prop은 템플릿 내부에서 사용할 수 있으며
// 인스턴스의 this.message로 사용할 수 있습니다.
template: '<span></span>'
})
</script>
camelCased 와 kebab-case
- javascript에서 camelCased 컨벤션을 이용해 작성할 경우 HTML의 표현은 조금 다르게 작성해야합니다.
- camelCased(대문자 사용) prop이름에 해당하는 HTML속성은 대소문자를 구분하지 않기 때문에 kebab-case(하이픈 구분)를 사용해야합니다.
<script>
Vue.component('child', {
// JavaScript는 camelCase
props: ['myMessage'],
template: '<span></span>'
})
</script>
<!-- HTML는 kebab-case -->
<child my-message="안녕하세요!"></child>
- 위 예제와 같이 myMessage prop에 해당하는 html은 my-message와 같이 작성해야합니다.
동적 Props
- v-bind를 이용해서 부모의 데이터에 props에 동적으로 바인딩 할 수 있습니다.
<div id="app">
<input v-model="parentMsg">
<br>
<child v-bind:my-message="parentMsg"></child>
<!--단축구문 <child :my-message="parentMsg"></child> -->
</div>
<script>
new Vue({
el: '#app',
data: {
parentMsg: 'default'
},
components: {
child: {
props: ['parentMsg'],
template: '<span> 동적 입력은 입니다. </span>'
}
}
})
</script>
- 객체의 모든 속성을 props로 전달하려면, 인자없이 v-bind:object 를 사용하면 됩니다.
<script>
todo: {
text: 'Learn Vue',
isComplete: false
}
</script>
<todo-item v-bind="todo"></todo-item>
<!-- 똑같은 구문입니다. -->
<todo-item
v-bind:text="todo.text"
v-bind:is-complete="todo.isComplete"
></todo-item>
단방향 데이터 흐름
- 모든 props는 상위에서 하위로 단방향 바인딩을 형성합니다.
- 이렇게함으로써 하위 컴포넌트가 실수로 부모의 상태를 변경하는것을 방지할 수 있습니다.
- prop을 변경시키고 싶은 두가지 경우
- 초기값을 전달하는데에만 사용하고 이후에는 지역 변수로서 사용하는 경우
- 해당 값을 재가공해서 사용하는 경우
- 두 가지의 경우 아래와 같은 방법으로 회피할 수 있습니다.
// 1번째 : 전달받은 값을 지역변수로 재정의합니다.
props: ['initialCounter'],
data: function () {
return { counter: this.initialCounter }
}
// 2번째 : 전달받은 값을 계산된 속성에 정의합니다.
props: ['size'],
computed: {
normalizedSize: function () {
return this.size.trim().toLowerCase()
}
}
Prop 데이터 검증
- props는 받는 데이터형을 지정해 두는 것이 권장되며, 스타일 가이드로는 필수로 지정하고 있습니다.
- 만약, 지정한 데이터형 이외에 다른 것을 넣으면 경고가 발생하여, 다른 사용자가 컴포넌트를 사용할 때 잘못 사용하는 오류를 방지할 수 있습니다.
Vue.component('example', {
props: {
// 기본 타입 확인 (`null` 은 어떤 타입이든 가능하다는 뜻입니다)
propA: Number,
// 여러개의 가능한 타입
propB: [String, Number],
// 문자열이며 꼭 필요합니다
propC: {
type: String,
required: true
},
// 숫자이며 기본 값을 가집니다
propD: {
type: Number,
default: 100
},
// 객체/배열의 기본값은 팩토리 함수에서 반환 되어야 합니다.
propE: {
type: Object,
default: function () {
return { message: 'hello' }
}
},
// 사용자 정의 유효성 검사 가능
propF: {
validator: function (value) {
return value > 10
}
}
}
})
- type으로 사용가능한 네이트브 생성자는 다음과 같습니다.
- String
- Number
- Boolean
- Function
- Object
- Array
- Symbol
- type은 커스텀 생성자 함수가 될 수 있고, 이때 검증은 instanceof로 확인합니다.
- props의 검증은 컴포넌트 인스턴스가 생성되기 전에 검증되기 때문에 default 또는 validator 함수 내에서 data, computed, methods와 같은 인스턴스 속성을 사용할 수 없습니다.(만들어지지 않았기 때문에)
Props에 정의되지 않은 속성
- 정의되지 않은 props는 attribute로 전달되었지만, 컴포넌트에 Props로 정의되지 않은 속성을 이야기합니다.
- 정의된 props는 하위 컴포넌트에 정보를 전달하는데 적합하지만, 다른 컴포넌트 라이브러리의 모든 경우를 예측할 수 없습니다.
- 이때 정의되지 않은 props를 사용하면 컴포넌트 루트 엘리먼트에 추가되어 다른 컴포넌트 라이브러리에서도 사용할 수 있습니다.
<script>
//bs-date-input컴포넌트 템플릿
Vue.component('bs-date-input', {
template: '<input type="date" class="form-control">'
})
</script>
<bs-date-input data-3d-date-picker="true"></bs-date-input>
<!-- 아래와 같은 html로 렌더링합니다 -->
<input type="date" class="form-control" data-3d-date-picker="true">
- 만약 상위에 지정한 속성이 하위에도 존재하는 경우, 보통은 상위에서 전달된 속성으로 교체 또는 병합(class, style)됩니다.
- 예를들어 아래와 같이 지정할 경우
<bs-date-input
type="large"
data-3d-date-picker="true"
class="date-picker-theme-dark"
></bs-date-input>
<!-- 아래와 같이 변경됩니다. -->
<input type="large" class="date-picker-theme-dark form-control" data-3d-date-picker="true">
- 만약 부모 컴포넌트에서 전달받은 attribtue를 사용하고 싶지 않을때는 inheritAttrs:false 을 지정하면 자식 컴포넌트의 attribute가 설정되지 않습니다. (기본값은 true입니다.)
- 아래와 같이 사용할 수 있습니다.
Vue.component('bs-date-input', {
inheritAttrs: false,
template: '<input type="date" class="form-control">'
})
- inheritAttrs와 $attrs를 이용하면 선택적으로 필요한 속성만 자식 컴포넌트에 설정할 수 있습니다.
ps. 찾아보고 공부하면서 정리하는 내용이라 틀릴 수 있음을 알려드립니다.
참고