기본적인 컴포넌트 설계 방식
container component
presentational component
// container component
<template>
<div>
<ChildComponent :items="items" @new="newItems"/>
</div>
</template>
<script>
import ChildComponent from '경로';
export default {
components: {
ChildComponent,
},
data() {
return {
items: [1, 2, 3],
}
},
methods: {
newItems() {
this.items = [10, 20, 30];
}
}
}
</script>
// presentational component
<template>
<div>
<ul>
<li v-for="item in items" :key="item.id">
{{ item.name }}
</li>
</ul>
<button @click="$emit('new')"> new items </button>
</div>
</template>
<script>
export default {
props: { // props validation 문법
items: {
type: Array, // 타입 정의
required: true, // 필수 값 속성
},
}
}
</script>
Slot을 이용하여 등록할때 컴포넌트를 확장하는 컴포넌트 디자인 설계 방식
// 부모 컴포넌트
<template>
<child-component>
<!-- slot에 나타낼 영역을 정의-->
<!-- 부모 컴포넌트에서 스타일 지정 가능 -->
<div slot="test1" style="font-size: 20px;">test1</div>
<!-- slot 속성으로 name 값과 매칭되는 슬롯에 연결 -->
<div slot="test2">test2</div>
</child-component>
</template>
// 자식 컴포넌트
<template>
<li>
<slot name="test1">
<!-- 등록하는 곳에서 정의할 화면 영역 -->
</slot>
<div>
<slot name="test2"> <!-- name 속성으로 연결 가능 -->
</slot>
</div>
</li>
</template>
하위 컴포넌트와 상위 컴포넌트 데이터가 밀착된 형태로 설계된 컴포넌트
하위에서 관리하고 있던 데이터를 상위에서 관리하게 만드는 방법
컴포넌트에 데이터 의존성 분리하는 것들이 디자인 패턴의 핵심
// 부모 컴포넌트
<template>
<!-- props로 값을 전달시 자식 컴포넌트에서 변경 불가 -->
<!-- v-model은 @input 이벤트와 :value 값으로 조작이 된다. -->
<CheckBox v-model="checked"/>
</template>
<script>
import CheckBox from '경로';
export default {
comonents: {
CheckBox,
},
data() {
return {
cehcekd: false,
}
}
}
</script>
// 자식 컴포넌트
<template>
<!-- 받을 때는 :value라는 props로 받고 올릴떄는 @input으로 올림 -->
<input type="checkbox" :value="value" @check="toggleCheckBox">
</template>
<script>
export default {
// @input 이벤트
// :value 값
props: ['value'],
methods: {
toggleCheckBox() {
this.$emit('input',!this.value);
}
}
}
</script>
templete
표현식이 없고 script
단에서 비즈니스 로직만 처리해서 상위 컴포넌트로로 데이터를 노출시켜주는 컴포넌트
데이터 제공만 하는 컴포넌트
// 부모 컴포넌트
<template>
<div>
<fetch-data url="https://jsonplaceholder.typicode.com/users/">
<!-- ... --> slot-scope 안에서만 데이터 접근 가능
<div v-slot:default="{ response, loading }">
<div v-if="!loading">
{{ response }}
</div>
<div v-else>
Loading...
</div>
</div>
</fetch-data>
</div>
</template>
<script>
import FetchData from '경로';
export default {
components: {
FetchData
}
}
</script>
// 자식 컴포넌트
<script>
import axios from 'axios';
export default {
props: ['url'],
data() {
return {
response: null,
loading: false,
}
},
created() {
axios.get(this.url)
.then(res => {
this.response = response.data;
this.loading = true;
})
.catch(err => {
console.log(err);
});
},
// render는 컴포넌트를 그리는 것
render() {
return this.$scopedSlots.default({
reponse: this.response,
loading: this.loading,
});
},
}
</script>
this.$scopedSlots.default()의 인자로 상위 컴포넌트에 범위가 있는 slot 데이터를 전달
template을 라이브러리 내부적으로 구현해주는 것
render: function(createElement) {
return createElement('태그 이름', '태그 속성', '하위 태그 내용');
}
// main.js
new Vue({
// 1, 2, 3, 4 다 같은 방법
render: h => h(App),
// 1
render: function(createElement) {
return createElement(App);
},
// 2, h => hyperScript(virtual DOM)을 지칭하는 용어
redner: function(h) {
return h(App);
},
// 3
render: h => {
return h(App);
},
// 4
render: h => h(App),
})