3. 뷰 컴포넌트 통신
3. 뷰 컴포넌트 통신
[컴포넌트간 통신과 유효범위]
- 뷰는 컴포넌트마다 자체적으로 고유한 유효범위를 갖는다. 따라서 다른 컴포넌트의 값을 직접적으로 참조할 수가 없다.
- 따라서 뷰에서 미리 정의해놓은 데이터 전달 방식에 따라 일관된 구조로 애플리케이션을 작성하게 된다.
[상하위 컴포넌트 관계]
- 기본적인 데이터 전달 방법이 상위 - 하위 컴포넌트 간의 데이터전달 방법이다.
- 상위 -> 하위 : props 라는 특별한 속성을 전달
- 하위 -> 상위 : 이벤트만 전달 가능
- 상위에서 하위 컴포넌트로 데이터 전달하기
// 하위 컴포넌트의 props 속성 정의 방식
Vue.component('child-component', {
props: ['props 속성 이름'],
});
<!-- 상위 컴포넌트의 HTML 코드 -->
<child-component v-bind:props 속성 이름 = "상위 컴포넌트의 data 속성"></child-component>
1. new Vue()로 인스턴스를 생성한다.
...
...
<body>
<div id="app">
</div>
<script src="~/vue.js"></script>
<script>
</script>
</body>
new Vue({
el:'#app',
data: {
message: 'Hello World'
}
});
2. Vue.component()로 하위 컴포넌트인 child-component를 등록한다. child-component 내용에 props 속성으로 propsdata를 정의한다.
Vue.component('child-component', {
props: ['propsdata'],
template: '<p>{{ propsdata }}</p>',
});
3. HTML에 컴포넌트 태그를 추가한다.
...
<body>
<div id="app">
<child-component v-bind:propsdata="message"></child-component>
</div>
<script src="~/vue.js"></script>
<script>
</script>
</body>
=> <child-component></child-component>는 <p>Hellow World</p>가 된다.
코드에 상위 컴포넌트를 지정하는 부분은 없다. 컴포넌트를 등록함과 동시에 뷰 인스턴스 자체가 상위 컴포넌트가 되기 때문이다.
- 하위 컴포넌트에서 상위 컴포넌트로 이벤트 전달하기
- 이벤트 발생: this.$emit('이벤트명'); // this는 거의 하위 컴포넌트. 보통 하위 컴포넌트 내부 특정 메서드에서 호출
- <child-component v-on:이벤트명="상위 컴포넌트의 메서드명"><child-component>
<div id="app">
<child-component v-on:show-log="printText"></child-component>
<div>
<script>
Vue.component('child-component', {
template:'<button v-on:click="showLog">show</button>',
methods: {
showLog: function() {
// 태그의 v-on:show-log와 매치. printText메서드가 호출됨
this.$emit('show-log');
}
}
});
new Vue({
el:'#app',
methods: {
printText: function() {
console.log("received an event");
}
}
});
</script>
1. show 버튼을 클릭하면 showLog() 메서드가 실행됨
2. showLog() 내부의 emit이 실행되면서 show-log 이벤트가 발생함
3. show-log는 <child-component>에 정의한 v-on:show-log에 전달되고 대상 메서드로 지정된 printText가 실행됨'
[같은 레벨의 컴포넌트간 통신]
뷰는 상위에서 하위로만 데이터를 전달해야하는 기본적인 통신 규칙을 따른다. 따라서 바로 옆 컴포넌트에 값을 전달하기 위해서는 하위에서 공통 상위 컴포넌트로 이벤트를 전달한 후, 공통 상위 컴포넌트에서 두 개의 컴포넌트에 props를 내려보내야 한다.
즉 상위 컴포넌트가 필요 없음에도 같은 레벨 간 통신을 위해 강제로 상위 컴포넌트를 두어야 한다.
=> 해결 방법은 이벤트 버스다.
- 이벤트 버스
- 개발자가 지정한 두 개의 컴포넌트 간에 데이터를 주고받을 수 있는 방법
- 이벤트 버스 형식
- 애플리케이션 로직을 담는 인스턴스와 별개로 새로운 인스턴스를 하나 더 생성한다. (var eventBus = new Vue();)
- 새 인스턴스를 이용해 이벤트를 주고 받는다. (보내기: eventBus.$emit(~), 받기: eventBus.$on(~)}
<div id="app">
<child-component></child-component>
</div>
<script>
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); // 100
});
}
});
</script>
1. 이벤트 버스로 활용할 새 인스턴스를 생성하고 eventBus라는 변수에 참조한다.
2. 하위 컴포넌트에는 template과 methods를 정의한다. methods에는 showLog()를 정의하고 메서드 안에 eventBus.$emit()을 선언하여 triggerEventBus라는 이벤트를 발생하는 로직을 추가한다. 이 때 인자로 100을 전달한다.
3. 상위 컴포넌트의 created 라이프 사이클 훅에 eventBus.$on()으로 이벤트를 받는 로직을 선언한다. 발생한 이벤트 triggerEventBus를 수신할 때 전달받은 100이 콘솔에 출력된다.
=> 이벤트 버스를 활용하면 props를 이용하지 않고도 원하는 컴포넌트 간에 직접적으로 데이터를 전달할 수 있어 편리하지만 컴포넌트가 많아지면 어디서 어디로 보냈는지 관리가 되지 않는다.
=> 이럴 때 뷰엑스라는 상태 관리 도구가 필요하다.
=>*vuex : 대형 애플리케이션에서 컴포넌트 간의 데이터 관리를 효율적으로 하는 라이브러리
궁금 1. 하위->상위 파라미터 전달도 가능한지?
궁금 2. $on을 여러 컴포넌트에서 정의하면 동시에 데이터를 받는건지?