컴포넌트란 화면을 구성하는 하나의 영역이다. 화면을 구조화하여 같은 패턴으로 개발하거나 재사용할 수 있게 해준다.
각 컴포넌트는 Root Component 밑에 있으며 Tree 형식을 가진다.
Single File Compoent 의 전역 컴포넌트와 지역 컴포넌트
- 전역 컴포넌트는 main.js 에서 Vue 변수에 component() 를 사용하여 등록하면 된다.
- 지역 컴포넌트는 export -> import 문으로 가져다가 쓸 수 있다. 보통 이 방법을 사용한다.
- 지역 컴포넌트는 Vue 생성자에 components 속성으로 {이름:컴포넌트} 를 기재한다.
import Vue from 'vue'
import App from './App.vue'
import globalComponent from "@/components/globalComponent";
Vue.config.productionTip = false
Vue.component('globalComponent',globalComponent);
new Vue({
render: h => h(App),}).$mount('#app')
<template>
<div id="app">
<BasicComp></BasicComp>
<global-component></global-component>
</div>
</template>
<script>
import BasicComp from "@/components/BasicComp";
export default {
components: { BasicComp}
}
</script>
<style>
</style>
지역 컴포넌트의 경우 사용되는 Vue Instance 범위까지 사용가능 하므로 유효 범위를 벗어나면 동작하지 않는다.
<template>
<div id="app">
<BasicComp></BasicComp>
<global-component></global-component>
</div>
<!-- 컴포넌트의 범위를 벗어남 -->
<BasicComp></BasicComp>
</template>
<script>
import BasicComp from "@/components/BasicComp";
export default {
components: {BasicComp}
}
</script>
<style>
</style>
컴포넌트 간의 통신 방법
- Component 단위로 구조화 하는 Vue 의 특성 상 Component 들에는 각자의 Scope 가 있기 때문에 Component 간에는 데이터를 공유하지 못한다.
- 그러므로 Vue 에서 개별적 컴포넌트 사이의 직접적 데이터 접근은 금지 된다.
- React 에서 가져온 단방향 데이터 흐름에 따라 부모 -> 자식 순으로 상위에서 하위로 데이터를 내려보내 주어야한다.
- 하위 컴포넌트에서 Event 를 발생 -> 상위 컴포넌트에서 props 를 내려줌.
- Event 에 Data 를 붙여서 전송 하려면 이벤트의 2 인자 값으로 data 를 주면 된다.
Props (Properties)
- props 속성은 상위에서 하위 컴포넌트로 내려주는 데이터 속성이다.
- 헷갈리면 안되는 것은 하위에서 props 속성을 정의하여 담을 데이터를 준비해야하는 것이다. props 속성은 Array 이다.
- 상위 컴포넌트에서는 내려보낼 data() {} 를 정의하고 v-bind:props="내려보낼데이터" 문법으로 데이터를 내려보낸다.
<template>
<div id="child">
Root Component Said : {{sendData}}
</div>
</template>
<script>
export default {
name: "ChildComponent",
props: ['sendData'], // array
}
</script>
<style scoped>
</style>
상위 컴포넌트
<template>
<div id="app">
<BasicComp></BasicComp>
<ChildComponent v-bind:send-data="responseData" ></ChildComponent>
<hr>
<global-component></global-component>
</div>
</template>
<script>
import BasicComp from "@/components/BasicComp";
import ChildComponent from "@/components/ChildComponent";
export default {
// 하위 컴포넌트 는 new Vue(components: { name : Component }) 로 정의
components: {BasicComp,ChildComponent},
data(){
return {
responseData: 'This is Response Data'
}
}
}
</script>
<style>
</style>
컴포넌트 간의 이벤트 발생 방법
- $emit() 은 하위에서 이벤트를 발생시키는 메서드이다. 인자로 이벤트 이름 , args 를 제공한다.
- 상위 컴포넌트에서는 v-on , @ 으로 이벤트 수신을 대기하다가 이를 받아 메서드를 호출한다.
하위 컴포넌트에서 올린 이벤트
<template>
<div id="child">
Root Component Said : {{sendData}}
<br>
<button @click="RequestEvent">Emit Event</button>
</div>
</template>
<script>
export default {
name: "ChildComponent",
props: ['sendData'],
methods: {
RequestEvent(){
this.$emit('event-name',1);
}
}
}
</script>
<style scoped>
</style>
상위 컴포넌트에서 수신 후 받는 메서드
<template>
<div id="app">
<BasicComp></BasicComp>
<ChildComponent @event-name="logData" v-bind:send-data="responseData" ></ChildComponent>
<hr>
<global-component></global-component>
</div>
</template>
<script>
import BasicComp from "@/components/BasicComp";
import ChildComponent from "@/components/ChildComponent";
export default {
// 하위 컴포넌트 는 new Vue(components: { name : Component }) 로 정의
components: {BasicComp,ChildComponent},
data(){
return {
responseData: 'This is Response Data'
}
},
methods: {
logData(number){
console.log(number);
}
}
}
</script>
<style>
</style>
결과
이벤트 송신과 내려보낼 데이터 바인딩을 이용해서 클릭시 데이터를 변경시키게 만들어본다.
- 기존의 데이터는 상위에서 새로 만들어지는 것이 아니라, 수정되는 것이다.
- Vue 의 Reactivity 를 이용하여 하위에서 데이터 변화를 감지, 양방향 데이터 바인딩으로 View 를 변경시킨다.
하위 컴포넌트에서 이벤트 송신
<template>
<div id="child">
Root Component Said : {{sendData}}
<br>
<button @click="RequestEvent">Emit Event</button>
</div>
</template>
<script>
export default {
name: "ChildComponent",
props: ['sendData'],
methods: {
RequestEvent(){
this.$emit('event-name',this.sendData);
}
}
}
</script>
<style scoped>
</style>
상위 컴포넌트에서 이를 받아 기존의 데이터를 수정
<template>
<div id="app">
<BasicComp></BasicComp>
<ChildComponent @event-name="UpdateData" v-bind:send-data="responseData" ></ChildComponent>
<hr>
<global-component></global-component>
</div>
</template>
<script>
import BasicComp from "@/components/BasicComp";
import ChildComponent from "@/components/ChildComponent";
export default {
// 하위 컴포넌트 는 new Vue(components: { name : Component }) 로 정의
components: {BasicComp,ChildComponent},
data(){
return {
responseData: ''
}
},
methods: {
UpdateData(data){
console.log(data);
this.responseData = 'Receive Event Request'
}
}
}
</script>
<style>
</style>
결과
같은 레벨의 컴포넌트간 통신 방법
- Vue 의 단방향 데이터 흐름으로 인해 같은 레벨의 컴포넌트 간에는 데이터 송신이 단계를 추가적으로 거친다.
- 트리가 깊어 질수록 거쳐 올라가야할 상위 컴포넌트가 많아지기 때문에 복잡해진다.
- 이를 해결하기 위해 Vue Instance 를 만들어 데이터를 보내는 Event Bus 를 제공한다.
SingeFileComponent 체계의 EventBus 활용
- javascript 파일로 Vue Instance 를 만들어 export 시킨다.
- Event Bus 사용하는 쪽에서 이를 import 시켜 이벤트와 데이터를 보낸다.
- 송신 : $.emit('name', data) | 수신 : $.on('name', function(data){})
이벤트 버스를 위한 js 파일
import Vue from 'vue'
export const EventBus = new Vue();
Event Bus 를 이용하여 송신
<template>
<div id="SiblingComponent1">
<h5>SiblingComponent1</h5>
{{data}}
<button @click="sendDataUsingEventBus">Send Data</button>
</div>
</template>
<script>
import {EventBus} from '../eventbus/event-bus.js'
export default {
name: "SiblingComponent1",
data(){
return {data:'Send Data To SiblingComponent2'}
},
methods:{
sendDataUsingEventBus(){
console.log("Call Event Bus")
EventBus.$emit('send',this.data);
}
}
}
</script>
<style scoped>
#SiblingComponent1{
border: black;
}
</style>
EventBus 를 이용하여 수신
<template>
<div id="SiblingComponent2">
<h5>SiblingComponent2</h5>
{{data}}
</div>
</template>
<script>
import {EventBus} from '../eventbus/event-bus.js'
export default {
name: "SiblingComponent2",
data(){
return {data: ''}
},
created() {
EventBus.$on('send',(sendData) => {this.data = sendData});
}
}
</script>
<style scoped>
</style>
결과
컴포넌트가 많으면 많을 수록 이벤트가 어디서 어디로 수신되는지 알 수 없기 때문에 Vuex 라는 상태관리도구를 사용한다.
'Vue.js' 카테고리의 다른 글
5.HTTP 통신, Axios (0) | 2020.12.17 |
---|---|
4.Router (0) | 2020.12.17 |
2.Vue Instance 와 속성, 라이프 사이클 (0) | 2020.12.17 |
1.Vue.js 기본 (0) | 2020.12.17 |
컴포넌트 구성 (0) | 2020.12.16 |