본문 바로가기

FrontEnd

Vuejs 뷰 컴포넌트 통신

728x90

컴포넌트 간 통신과 유효 범위

<!DOCTYPE html>
<html lang="ko" dir="ltr">
  <head>
    <meta charset="utf-8">
    <title>Vue sample</title>
  </head>
  <body>
    <div id="app">
      <my-component1></my-component1>
      <my-component2></my-component2>
    </div>
    <script src="https://cdn.jsdelivr.net/npm/vue@2.5.2/dist/vue.js"></script>
    <script>
      //지역 컴포넌트 내용
      var cmp1 = {
        template: '<div>첫 번째 지역 컴포넌트 : {{ cmp1Data }}</div>',
        data : function(){
          return{
            cmp1Data : 100
          }
        }
      };
      var cmp2 = {
        template: '<div>두 번째 지역 컴포넌트 : {{ cmp2Data }}</div>',
        data : function() {
          return{
            cmp2Data : cmp1.data.cmp1Data
          }
        }
      };
      new Vue({
        el: '#app',
        //지역 컴포넌트 등록
        components : {
          'my-component1' : cmp1,
          'my-component2' : cmp2
        }
      });
    </script>
  </body>
</html>

 

2개의 지역 컴포넌트를 등록하고 한 컴포넌트에서 다른 컴포넌트의 값을 직접 참조하는 예제

my-component2 컴포넌트 내용에서 {{cmp2Data}}가 my-component1 컴포넌트의 data.cmp1Data를 참조하고 있다

 

아무것도 값이 나오지 않은 이유는 my-component2에서 my-component1의 값을 직접 참조할 수 없기 때문이다

 

 

상-하위 컴포넌트 관계

: 트리 구조에서 부모노드, 자식노드처럼 컴포넌트 간의 관계가 부모, 자식으로 이루어진 컴포넌트를 의미

지역 또는 전역 컴포넌트를 등록하면 등록된 컴포넌트는 하위 컴포넌트(자식 컴포넌트)가 된다. 하위 컴포넌트를 등록한 인스턴스는 상위 컴포넌트(부모 컴포넌트)가 된다

https://kouzie.github.io/vue/Vue-%EC%8A%A4%ED%83%80%EC%9D%BC,-%EC%BB%B4%ED%8F%AC%EB%84%8C%ED%8A%B8/

 

props 속성 : 상위 컴포넌트에서 하위 컴포넌트로 데이터를 전달할 때 사용하는 속성

Vue.component('child-component', {
	props: ['props 속성 이름'],
});

 

<child-component v-bind:props 속성 이름="상위 컴포넌트의 data 속성"></child-component>

v-bind 속성의 왼쪽 값으로 하위 컴포넌트에서 정의한 props 속성을 넣고, 오른쪽 값으로 하위 컴포넌트에 전달할 상위 컴포넌트의 data 속성을 지정

 

<!DOCTYPE html>
<html lang="ko" dir="ltr">
  <head>
    <meta charset="utf-8">
    <title>Vue sample</title>
  </head>
  <body>
    <div id="app">
      <child-component v-bind:propsdata="message"></child-component> <!--props 속성 이름, 상위 컴포넌트 데이터 속성-->
    </div>
    <script src="https://cdn.jsdelivr.net/npm/vue@2.5.2/dist/vue.js"></script>
    <script>
      Vue.component('child-component', { //하위 컴포넌트인 child-component를 등
        props: ['propsdata'], //props 속성으로 propsdata 정 
        template: '<p>{{propsdata}}</p>', //template속성에 정의된 것이 message가 되는 것
      })
      //인스턴스 하나 생성
      new Vue({
        el: '#app',
        data : {
          message : 'Hello Vue! passed from parent component'
        }
      });
    </script>
  </body>
</html>

 

뷰 인스턴스 안에 상위 컴포넌트가 존재하는 것처럼 하위 컴포넌트로 props를 내려보냈다. 그 이유는 컴포넌트를 등록함과 동시에 뷰 인스턴스 자체가 상위 컴포넌트가 되기 때문

 

 

하위 컴포넌트에서 상위 컴포넌트로 이벤트 전달하기

-> 이벤트(evnet emit)를 발생시켜 상위 컴포넌트에 신호를 보내면 된다

 

상위 컴포넌트에서 하위 컴포넌트의 특정 이벤트가 발생하기를 기다리고 있다가 하위 컴포넌트에서 특정 이벤트가 발생하면 상위 컴포넌트에서 해당 이벤트를 수신하여 상위 컴포넌트의 메서드를 호출하는 것

 

이벤트 발생

this.$emit('이벤트명');

 

이벤트 수신

<child-component v-on:이벤트명="상위 컴포넌트의 메서드명"></child-component>

 

$emit()을 호출하면 괄호 안에 정의된 이벤트가 발생

일반적으로 $emit()을 호출하는 위치는 하위 컴포넌트의 특성 메서드 내부이다. 따라서 이벤트를 호출할 때 쓰는 this는 하위 컴포넌트를 가리킨다

 

호출한 이벤트는 하위 컴포넌트를 등록하는 태그(상위 컴포넌트의 template 속성에 위치)에서 v-on: 속성에 지정하고, 속성의 값에 이벤트가 발생했을 때 호출될 상위 컴포넌트의 메세지를 지정

 

<!DOCTYPE html>
<html lang="ko" dir="ltr">
  <head>
    <meta charset="utf-8">
    <title>Vue sample</title>
  </head>
  <body>
    <div id="app">
      <child-component v-on:show-log="printText"></child-component> <!--하위 컴포넌트 이벤트명 상위="컴포넌트의 메서드명"-->
    </div>
    <script src="https://cdn.jsdelivr.net/npm/vue@2.5.2/dist/vue.js"></script>
    <script>
      Vue.component('child-component', {
        template: '<button v-on:click="showLog">show</button>', //버튼 요소 추가
        //메서드 추가
        methods: {
          showLog: function(){
            this.$emit('show-log'); //이벤트 발생 로직
          }
        }
      });
      var app = new Vue({
        el: '#app',
        data: {
          message : 'Hello Vue! passed from parent component'
        },
        methods: {
          printText: function(){ //콘솔에 로그가 출력됨
            console.log("received an event");
          }
        }
      });
    </script>
  </body>
</html>

 

개발자 도구로 보면 출력된 것을 확인할 수 있다

 

 

같은 레벨에 있는 컴포넌트 간 통신

https://brainmemory.tistory.com/51

옆 컴포넌트에 값을 전달하려면 하위에서 공통 상위 컴포넌트로 이벤트를 전달한 후 공통 상위 컴포넌트에서 2개의 하위 컴포넌트에 props를 내려보내야 한다

 

 

관계 없는 컴포넌트 간 통신 - 이벤트 버스

https://rwd337.tistory.com/134

이벤트 버스(event bus) : 개발자가 지정한 2개의 컴포넌트 간에 데이터를 주고 받을 수 있는 방법

상위-하위 구조를 유지하고 있지 않더라도, 데이터를 한 컴포넌트에서 다른 컴포넌트로 전달할 수 있다

 

그림처럼 기존의 구조는 저렇게 하위컴포넌트->상위컴포넌트->최상위컴포넌트->하위컴포넌트 이런 식으로 전달해야 하지만

뷰에서는 하위컴포넌트B에서 상위 컴포넌트A로 바로 데이터를 전달할 수 있다!!!!

 

이벤트 버스 형식

//이벤트 버스를 위한 추가 인스턴스 1개 생성
var eventBus = new Vue();

 

//이벤트를 보내는 컴포넌트
methods: {
	메서드명: function(){
    	eventBus.$emit('이벤트명', 데이터);
    }
}

 

//이벤트를 받는 컴포넌트
methods: {
	created: function(){
    	eventBus.$on('이벤트명', function(데이터){
        	...
        });
    }
}

 

show 버튼을 클릭했을 때 이벤트 버스를 이용하여 상위 컴포넌트로 데이터를 전달하는 코드

<!DOCTYPE html>
<html lang="ko" dir="ltr">
  <head>
    <meta charset="utf-8">
    <title>Vue sample</title>
  </head>
  <body>
    <div id="app">
      <child-component></child-component>
    </div>
    <script src="https://cdn.jsdelivr.net/npm/vue@2.5.2/dist/vue.js"></script>
    <script>
      var eventBus = new Vue(); //이벤트버스로 사용할 새 인스턴스 1개 생성, eventBus 변수에 참조. evnetBus 변수로 새 인스턴스의 속성과 메소드 접근 가능
      Vue.component('child-component', {
        template: '<div>하위 컴포넌트 영역입니다. <button v-on:click="showLog">show</button></div>',
        methods: { //메서드 속성
          showLog: function(){
            eventBus.$emit('triggerEventBus', 100); //수신하는 쪽에 인자값으로 100이라는 숫자 전달
          }
        }
      });
      var app = new Vue({
        el: '#app',
        created: function(){ //상위 컴포넌트의 created 라이프사이클
          eventBus.$on('triggerEventBus', function(value){
            console.log("received an event, value is ", value);
          });
        }
      });
    </script>
  </body>
</html>

 

show 버튼을 클릭하여 showLog()가 실행되었을 때 eventBus의 이벤트가 발생

발생한 이벤트는 상위 컴포넌트의 created()에 있는 eventBus.$on()에서 전달받는다. 그리고 이벤트와 함께 전달된 인자 값 100이 콘솔 로그와 함께 출력됨!

 

이벤트 버스 장점

- props 속성을 이용하지 않고 원하는 컴포넌트 간에 직접적으로 데이터를 전달 가능

 

이벤트 버스 단점

- 컴포넌트가 많아 지면 어디서 어디로 보냈는지 관리 X -> 해결하려면 Vuex라는 상태관리 도구 필요

 

728x90

'FrontEnd' 카테고리의 다른 글

뷰 템플릿  (0) 2022.08.05
Vue.js 뷰 HTTP 통신  (0) 2022.07.28
Vue.js 뷰 라우터 | 네스티드 뷰 | 네임드 뷰  (0) 2022.07.28
Vue.js 컴포넌트  (0) 2022.07.25
Vue.js 기초 | 라이프사이클  (0) 2022.07.25