Vue.js

3.Component

Jungsoomin :) 2020. 12. 17. 15:35

컴포넌트란 화면을 구성하는 하나의 영역이다. 화면을 구조화하여 같은 패턴으로 개발하거나 재사용할 수 있게 해준다.

 

각 컴포넌트는 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 를 제공한다.

Event Bus 는 새로운 Vue Instance 를 통해 데이터를 전달하고 받는 방식이다.

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