Vue로 작업을 하다 보면, 컴포넌트 안에 컴포넌트를 구성하여서 작업을 해야하는 경우가 있다. 나의 경우에는, 컴포넌트 안에 그래프 컴포넌트를 구성하여 작업한 적이 있다.
그 때, 부모 컴포넌트에서 자식 컴포넌트로 데이터를 전달해야 하는 경우가 생기는데 이런 경우에 사용하는데 Props 이다.
부모 컴포넌트와 자식 컴포넌트에 대해서 우선 간단하게 알아보고 가겠다. 위의 예시처럼 어떤 컴포넌트 안에 하나 또는 둘 이상의 컴포넌트를 종속시켜서 활용하는 경우가 생긴다.
이때 다른 컴포넌트를 감싸안는 더 큰 컴포넌트를 부모 컴포넌트라고 하고, 부모 컴포넌트에 종속되는 컴포넌트를 자식 컴포넌트라고 부른다.
다른 말로 각각 상위 컴포넌트, 하위 컴포넌트라고 부르기도 한다.
부모 컴포넌트에서 하위 컴포넌트로 데이터를 전달해야 하는 상황이 생기는데 이 때 사용하는 것이 Props이다.
예를 들어 데이터를 분석하는 페이지를 만들고자 한다. 페이지 레이아웃을 만들고 그 안에 그래프를 넣어야 하는데, 이 때 그래프를 별도의 컴포넌트로 구성하여 넣으려 한다.
이 때 레이아웃 페이지는 부모 컴포넌트가 되고, 그래프 컴포넌트를 자식 컴포넌트가 된다.
부모 컴포넌트에서는 메소드를 이용해 데이터를 가져올 것이다. 그래프 컴포넌트에서는 그 데이터를 이용해서 그래프를 그려야하는데 부모 컴포넌트에서 그 데이터를 받아와야 한다.
부모 컴포넌트에서 자식 컴포넌트로 데이터를 전달하기 위해서는 부모 컴포넌트에서 자식 컴포넌트를 HTML 태그로 불러온 후 태그 안에서 데이터를 넘겨주면 된다.
# parent component
<template>
<child msg="Hello"></child>
</template>
HTML 태그 안에 데이터를 정의해주면 자식 컴포넌트에서 데이터를 받을 수 있게 된다.
유의할 점은 위에서 사용된 방식은 동적인 바인딩이 아니라는 것이다. 따라서 데이터가 바뀌더라도 하위 컴포넌트는 이를 반영하지 못한다.
v-bind
를 이용하면 데이터를 동적으로 넘길 수 있다. 즉, 데이터가 변하게 되면 자식 컴포넌트에서도 이 변화를 감지하고 반영하게 된다.
# parent component
<template>
<input v-model="parentMsg">
<br>
<child v-bind:msg="parentMsg"></child>
</template>
이런식으로 v-bind
를 이용해 데이터를 전달해주면 동적으로 데이터가 전달된다. parentMsg
에 입력된 값이 바뀌면 자식 컴포넌트로도 변화된 값이 재전달될 것이다.
v-bind:
는 :
라는 약어로도 쓸 수 있고 실제로 이 방식이 더 많이 쓰인다.
# parent component
<template>
<input v-model="parentMsg">
<br>
<child :msg="parentMsg"></child>
</template>
위처럼 부모 컴포넌트에서 전달된 데이터는 자식 컴포넌트에서 Props를 이용해 받을 수 있다.
# child component
export default {
props: {
msg: String
}
이런식으로 변수의 유형을 결정해두면 된다.
1. 타입 지정
export default {
props: {
msg: Number
}
→ msg는 숫자 타입이다.
Prop은 다음 유형들을 지정할 수 있다.
String, Number, Boolean, Function, Object, Array, Symbol
'null'로 지정하면 어떤 유형이든 가능하다는 뜻이 된다.
2. 여러 개의 가능한 타입
export default {
props: {
msg: [String, Number]
}
→ msg는 문자열이나 숫자 타입이어야 한다.
3. 필수 여부 지정
export default {
props: {
msg: {type: String,
required: true
}
}
→ msg는 문자열이며 필수 값이다.
4. 기본값 지정
export default {
props: {
msg: {type: String,
default: 'Hello'
}
}
→ msg는 문자열이며 기본 값은 'Hello'이다.
5. 함수 값 반환
export default {
props: {
msg: {type: Object,
default: function () {
return { message: 'hello' }
}
}
}
→ msg는 객체이며 기본 값은 함수에서 반환된다.
Props에 대한 개념이 확실하지 않은 상황에서 chart.js를 사용하려다가 골머리를 앓았던 기억이 있어서 이 예시를 준비했다.
부모 컴포넌트에서 페이지 레이아웃을 만들고 자식 컴포넌트에서 Chart.js 라이브러리를 이용한 그래프를 구성하려고 한다.
<부모 컴포넌트>
<template>
<h1>원 그래프</h1>
<PieChart
:data1 = "50"
:data2 = "30"
:data3 = "20">
</PieChart>
</template>
<script>
//자식 컴포넌트 불러오기
import PieChart from '@/components/chart/Pie.vue'
export default {
components: { PieChart }
}
</script>
부모 컴포넌트에서 data1,2,3에 각각 50,30,20 을 전달했다.
<자식 컴포넌트(그래프)>
<template>
<Pie
:chart-options="chartOptions"
:chart-data="chartData"
/>
</template>
<script>
import { Pie } from 'vue-chartjs/legacy'
import {
Chart as ChartJS,
Title,
Tooltip,
Legend,
ArcElement,
CategoryScale
} from 'chart.js'
ChartJS.register(Title, Tooltip, Legend, ArcElement, CategoryScale)
export default {
name: 'PieUserChart',
components: {
Pie
},
props: {
data1: {
type: Number
},
data2: {
type: Number
},
data3: {
type: Number
}
},
// 값이 바뀔때마다 dataset 재설정하기
watch: {
percentCarbohydrate () {
this.chartData.datasets[0].data = [parseInt(this.data1), parseInt(this.data2), parseInt(this.data3)]
}
},
data () {
return {
chartData: {
labels: ['탄수화물', '단백질', '지방'],
datasets: [
{
label: '권장 섭취량',
backgroundColor: ['#ffce56', '#37a2eb', '#fe6484'],
data: []
}
]
},
chartOptions: {
responsive: true,
maintainAspectRatio: false
}
}
}
}
</script>
자식 컴포넌트에서는 Props를 이용해 부모 컴포넌트로부터 받아온 data1,2,3을 전달받고 이를 데이터셋에 설정하여 그래프를 완성시킨다.
(수많은 옵션 등의 기본 설정들은 간략한 예시를 위해 모두 지웠다)
<참조>