컴포넌트끼리 통신가능?
앵귤러, 백본같은 초기 자바스크립트 프레임워크의 경우, 한 화면을 한개의 뷰로 간주
vue.js는 컴포넌트로 화면을 구성하므로, 같은 웹 페이지라도 데이터 공유 가능.
(컴포넌트마다 자체적으로 고유한 유효범위(scope)이 있기때문에)
<html> <head> <title>Vue Component Scope</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>
자바스크립트 객체 방식으로 보면, cmp2Data는 my-component1의 data를 참조하고 있지만, 값을 출력할 수 없음.
이유는, 값을 직접 참조할 수 없기 때문. 이렇게 다른 컴포넌트 값을 참조할 수 없기 때문에, 데이터 전달 방식에 따라 일관된 구조로 애플리케이션 작성이 가능.
상위, 하위 컴포넌트 관계
가장 기본적인 데이터 전달 방법: 상위(부모) - 하위(자식) 컴포넌트 간의 데이터 전달
상위에서 하위는 props라는 특별한 속성을 전달.
하위에서 상위로는 기본적으로 이벤트만 전달.
상위에서 하위로 데이터 전달하기
props 속성
props: 상위에서 하위로 데이터 전달할 때 사용.
1. 하위 컴포넌트 속성 정의
Vue.component('child-component', { props: ['props 속성 이름'], });
2. HTML 코드에 등록된 child-component 컴포넌트 태그에 v-bind 속성을 추가.
<child-component v-bind:props 속성 이름="상위 컴포넌트의 data 속성"></child-component>
v-bind 속성의 왼쪽값에 하위 컴포넌트에서 정의한 props(아래에선 propsdata)를 넣고,
오른쪽 값으로 하위 컴포넌트에 전달할 상위 컴포넌트의 data 속성(아래에선 message)을 지정.
예제
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Vue Props Sample</title> </head> <body> <div id="app"> <!-- 팁 : 오른쪽에서 왼쪽으로 속성을 읽으면 더 수월합니다. --> <child-component v-bind:propsdata="message"></child-component> </div> <script src="https://cdn.jsdelivr.net/npm/vue@2.5.2/dist/vue.js"></script> <script> Vue.component('child-component', { props: ['propsdata'], template: '<p>{{ propsdata }}</p>', }); new Vue({ el: '#app', data: { message: 'Hello Vue! passed from Parent Component' } }); </script> </body> </html>
코드 순서대로 봐보자!
- new Vue()로 인스턴스를 생성
- Vue.component()를 이용하여 하위 컴포넌트인 child-component를 등록.
- child-component의 내용에 props 속성으로 propsdata를 정의
컴포넌트의 관계?
child-component를 전역으로 등록한거 외에는 상위 컴포넌트 지정이 없었음. 어떻게 될까?
그 이유는 컴포넌트를 등록함과 동시에 뷰 인스턴스 자체가 상위 컴포넌트가 되기 때문.
하위에서 상위 컴포넌트로 이벤트 전달
하위에서 상위로 보낼땐, 이벤트를 발생시켜 상위 컴포넌트에 신호를 보내면 됨.
상위 컴포넌트에서 하위 컴포넌트의 특정 이벤트가 발생하기를 기다리고 있다가,
하위 컴포넌트에서 특정 이벤트가 발생하면 상위 메소드를 호출.
이벤트 발생과 수신 형식
$emit()과 v-on: 속성을 사용하여 구현.
// 이벤트 발생
this.$emit('이벤트명')';
// 이벤트 수신
<child-component v-on:이벤트명="상위 컴포넌트의 메소드명"></child-component>
예제
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Vue Event Emit 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'); } } }); new Vue({ el: '#app', data: { message: 'Hello Vue! passed from Parent Component' }, methods: { printText: function() { console.log("received an event"); } } }); </script> </body> </html>
- show 버튼 클릭시, 클릭 이벤트 v-on:click="showLog"에 따라 showLog() 메소드가 실행
- showLog() 메소드 안에 this.emit('show-log')가 실행 show-log 이벤트 발생
- show-log 이벤트는 <child-component>에서 정의한 v-on:show-log에 전달, v-on:show-log의 대상 메소드인 최상위 컴포넌트의 메소드 printText()가 실행
- printText()는 received an event 라는 로그를 출력하는 메소드, 마지막에 로그가 출력
이렇게 하위 컴포넌트-> 상위 컴포넌트 메소드 실행도 가능. 하위 컴포넌트로 내려보내는 props값 조정도 가능
같은 레벨의 컴포넌트 간 통신
상위에서 하위로 props 전달, 하위에서 상위로 이벤트 전달. 그렇다면 같은 레벨의 컴포넌트끼리의 통신은?
Vue는 상위에서 하위로만 데이터를 전달해야 하는 기본적인 통신 규칙을 따름 옆 컴포넌트에 전달하려면, 하위에서 공통 상위 컴포넌트로 이벤트를 전달한 후 공통 상위 컴포넌트에서 2개의 하위 컴포넌트에 props를 내려보내야 함.
하지만, 이런 통신 구조를 유지하려면, 불필요하게 상위 컴포넌트를 만들어야 함;
이를 해결할 수 있는 방법이 바로 이벤트 버스!
관계없는 컴포넌트 간 통신 - 이벤트 버스
이벤트 버스는 개발자가 지정한 2개의 컴포넌트 간에 데이터를 주고 받을 수 있는 방법.
상위-하위 관계를 유지하지 않아도 컴포넌트 to 컴포넌트 데이터 전달이 가능
// 이벤트 버스를 위한 추가 인스턴스 1개 생성 var eventBus = new Vue(); //이벤트를 보내는 컴포넌트 methods: { 메소드명: function(){ eventbus.$emit('이벤트명', 데이터); } } //이벤트를 받는 컴포넌트 methods: { created: function() { eventBus.$on('이벤트명', function(데이터) { ... }); } }
1. 새 이벤트 생성
2. 하위컴포넌트에는 template 속성과 methods 속성 정의.
3. 상위 컴포넌트의 created 라이프 사이클 훅에 eventBus.$on()으로 이벤트를 받는 로직 선언. 발생한 이벤트
triggerEventBus를 수신할 때 앞에서 전달된 인자 값 100이 콘솔에 출력.
이벤트 버스를 활용하면 props 사용 없이 컴포넌트에 데이터 전달이 가능하나, 컴포넌트가 많아지면, 어디에서 보내졌는지 관리가 되지 않음. 이것 때문에 vuex라는 상태관리도구가 필요.
'IT > Vue.js' 카테고리의 다른 글
[vue.js] vue HTTP 통신 (Axios) (0) | 2021.02.20 |
---|---|
[vue.js] vue 라우터 (0) | 2021.02.20 |
[vue.js] 컴포넌트(component) (0) | 2021.02.19 |
[vue.js] 인스턴스(instance) (0) | 2021.02.19 |
quasar axios 적용 (0) | 2020.08.05 |