뷰에서는 상위에서 하위로의 데이터 흐름(단방향 데이터 흐름)을 규약으로 지키며 구현한다.
먼저,
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 |