본문 바로가기
Vue.js

Vue.js - #6 데이터 흐름(상-하, 하-상, 동일), 이벤트 버스(Event Bus)

by #Glacier 2021. 10. 24.
반응형

뷰에서는 상위에서 하위로의 데이터 흐름(단방향 데이터 흐름)을 규약으로 지키며 구현한다.

 

먼저, 

 

1) 상위에서 하위로 데이터를 보낼 때

 

props 속성을 사용하여 상위 컴포넌트에서 하위 컴포넌트로 보낸다.

먼저, 하위 컴포넌트에 속성에 props 속성을 정의하고,

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

상위 컴포넌트의 HTML 코드에 등록된 child-component 태그에 v-bind 속성을 추가한다.

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

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

 

예제로, 

<div id="app">
	<child-component v-bind:propsdata="message"></child-component>
</div>
Vue.component('child-component', {
	props : ['propsdata'],
    template : '<p>{{propsdata}}</p>',
});

new Vue({
	el : '#app',
    data : {
    	message : 'Hello Vue!'
    }
});

그러면, 상위 컴포넌트의 message 값인 'Hello Vue!'값이 하위 컴포넌트인 propsdata로 전달되어 화면에 나타난다.

여기서 중요한 점은, child-component를 전역으로 등록한 것 말고는 상위 컴포넌트를 지정하지 않았음에도 불구하고,

뷰 인스턴스 안에서 상위->하위로 props를 보냈다는 점이다. 그 이유는 컴포넌트를 등록하면, 뷰 인스턴스 자체가 상위 컴포넌트가 되기 때문이다.

즉, 인스턴스에 새로운 컴포넌트를 등록하면, 기존에 있는 컴포넌트는 상위 컴포넌트가 되고, 새로 등록된 컴포넌트는 하위 컴포넌트가 된다.

 

2) 하위에서 상위로 보낼 때

 

하위에서 상위로 데이터를 전달하는 방법은 사실 룰에 어긋난다. 공식 사이트에서도 하위->상위로 전달하는 방법을 다루지 않는다. 하지만 사용하는 방법은 다음과 같다.

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

 

이벤트의 발생은 $emit(), 이벤트의 수신은 v-on: 속성을 사용한다.

<div id = "app">
  <child-component v-on:show-log="printText"></child-component>
</div>
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("receive an event");
    }
  }
});

생성된 show 버튼을 클릭하면, v-on:click="showLog"에 따라 showLog() 메서드가 실행되고,

this.$emit('show-log');를 통해 show-log 이벤트가 발생한다.

show-log 이벤트는 child-component에서 정의한 v-on:show-log에 전달되고, v-on:show-log의 대상 메서드인

최상위 컴포넌트의 printText()가 실행되어 console.log("receive an event")가 실행되게 된다.

즉 이렇게 하위 컴포넌트에서 상위로 데이터가 전달되게 된 셈이다.

 

 

2) 동등한 관계(같은 레벨의 컴포넌트 간 통신)

동등한 관계에서는 서로 아무 관계가 없는 컴포넌트이므로 전달할 방법이 없다.

컴포넌트 고유의 유효 범위 때문에, 다른 컴포넌트의 값을 직접 참조할 수 없기 때문이다.

따라서 데이터 전달 방식을 활용하여 같은 레벨 간에 통신이 가능하도록 구조를 갖춰야 한다.

 

만약 

 

                    최상위 컴포넌트(루트 컴포넌트)

            상위 A 컴포넌트            상위 B 컴포넌트

            하위 A 컴포넌트            하위 B 컴포넌트

 

이런 상황일 때, 하위 A 컴포넌트에서 동등 레벨에 있는 하위 B 컴포넌트에 데이터를 전달하기 위해서는

하위 A -> 상위 A -> 최상위 -> 상위 B -> 하위 B로 전달되게 될 것이다.

매우 불필요하고, 이런 경우를 유지하다 보면, 같은 레벨 간에 통신을 위해 억지로 상위 컴포넌트를 두게 된다.

 

이러한 것을 해결해주는 것이 바로 "이벤트 버스"이다.

이벤트 버스는 개발자가 지정한 2개의 컴포넌트 간에 데이터를 주고 받을 수 있는 방법으로, 

상-하 관계를 갖지 않아도 서로 다른 컴포넌트에 데이터를 전달할 수 있다.

 

이벤트 버스는 애플리케이션 로직을 담는 인스턴스와는 별개로 새로운 인스턴스를 한 개 더 생성하고,

새 인스턴스를 이용하여 이벤트를 보내고 받는다.

보내는 컴포넌트에서는 .$emit(), 받는 컴포넌트에서는 .$on()을 사용한다.

<div id = "app">
  <child-component></child-component>
</div>
var eventBus = new Vue();

Vue.component('child-component', {
  template : '<div>하위 컴포넌트 영역입니다.<button v-on:click="showLog">show</button></div>',
  methods : {
    showLog : function() {
      eventBus.$emit('triggerEventBus', 100);
    }
  }
});

var app = new Vue({
  el : '#app',
  created : function() {
    eventBus.$on('triggerEventBus', function(value){
      console.log("이벤트를 전달받음. 전달받은 값 : ", value);
    }); 
  }
})

새로운 인스턴스를 생성하고, eventBus라는 변수에 참조한다.

eventBus라는 변수로 이제 인스턴스 내의 속성에 접근할 수 있다.

 

간단히 정리하면, show버튼을 클릭하여, showLog()가 실행되었을 때, eventBus가 발생하게 되고,

showLog라는 메서드에 따라 triggerEventBus라는 이벤트가 발생하며 100이라는 값을 전달한다.

 

상위 컴포넌트의 created 라이프사이클 훅에 eventBus.$on()으로 이벤트를 받고, 값을 받아 콘솔에 출력하게 된다.

여기서 처음 듣는 것이 라이프사이클일텐데. 다음 번에 둘러보자~


그러나, 이렇게 편리하게 보낼 수 있지만, 컴포넌트가 많아지는 경우 어디서 어디로 보냈는지 관리가 되지 않는다.
이 문제를 해결하려면, 뷰엑스(Vuex)라는 상태 관리 도구가 필요하지만 입문 레벨에서는 필수조건이 아니다.


참고로 뷰엑스는 대형 애플리케이션에서 컴포넌트 간의 데이터 관리를 효율적으로 하는 라이브러리다.

다음에는 실습 해보고, 라이프사이클에 대해서 공부해보자~

반응형

'Vue.js' 카테고리의 다른 글

Vue 시작하기  (1) 2022.10.28
Vue.js - #5 사용자 입력 제어, v-on:click, 함수 사용  (0) 2021.10.15
Vue.js - #4 디렉티브, 반복문  (0) 2021.10.15
Vue.js - #3 Vue Instance  (0) 2021.10.09
Vue.js - #2 환경 구성  (0) 2021.10.07