티스토리 뷰
컴포넌트 간 통신과 유효범위
뷰는 컴포넌트로 화면을 구성하기 때문에 같은 웹페이지라도 데이터를 공유할 수 없습니다.
각 컴포넌트마다 자체적으로 고유한 유효범위(scope)를 갖기 때문이죠!
즉, 다른 컴포넌트 값을 직접 참조할 수 없습니다.
예제1
예제 1
<htlml>
<head>
<title>뷰 컴포넌트 통신</title>
</head>
<body>
<div id="app">
<local-component1></local-component1>
<local-component2></local-component2>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.2/dist/vue.js"></script>
<script>
//첫 번째 컴포넌트 내용 선언
var cmp1 = {
template: '<h1>첫 번째 지역 컴포넌트 : {{ cmp1Data }} </h1>',
data: function(){
return {
cmp1Data : 100
}
}
};
//두 번째 컴포넌트 내용 선언
var cmp2 = {
template: '<h1>두 번째 지역 컴포넌트 : {{ cmp2Data }} </h1>',
data: function(){
return {
cmp2Data : cmp1.data.cmp1Data
}
}
};
//뷰 인스턴스 생성
new Vue({
el: '#app',
components: {
'local-component1' : cmp1,
'local-component2' : cmp2
}
});
</script>
</body>
</htlml>

{{ cmp2Data }} 의 cmp1.data.cmp1Data 가 적용되지 않은 결과를 확인할 수 있다.
즉, local-component2에서 local-component1를 직접 참조할 수 없다.
상/하위 컴포넌트 관계
뷰 프레임워크 자체에서 정의한 컴포넌트 데이터 전달 방법을 따라 데이터를 전달해야한다.
가장 기본적인 방법은 바로 상위(부모) - 하위(자식) 컴포넌트 간의 데이터 전달 방법이다.
상위-하위 컴포넌트의 데이터 전달은 아래와 같이 이루어집니다.
상위(부모) 컴포넌트 |
이벤트발생 <------ ------> props 전달 |
하위(자식) 컴포넌트 |
상위에서 하위 컴포넌트로 데이터 전달하기
props 속성을 사용하면 됩니다. 이는 상위 컴포넌트에서 하위 컴포넌트로 데이터를 전달할 때 사용하는 속성입니다.
//하위 컴포넌트의 props 속성 정의방식
Vue.component('child-component', {
props: ['props 속성이름'],
});
<child-component v-bind:props속성이름="상위컴포넌트의 data 속성"></child-component>
v-bind 왼쪽 값으로 하위 컴포넌트에서 정의한 props속성을 넣고, 오른쪽 값으로 상위 컴포넌트의 data속성을 지정한다.
예제2
예제2
<htlml>
<head>
<title>뷰 컴포넌트 통신</title>
</head>
<body>
<div id="app">
<!--4. HTML 컴포넌트 태그추가 (v-bind 속성 등록)-->
<!--상위 컴포넌트의 message 속성 값인 'Hello Vue! passed from Parent Component' 텍스트를 하위 컴포넌트의 propsdata로 전달하였음.-->
<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>
//2. 하위 컴포넌트 등록
Vue.component('child-component',{
//3. props 속성 정의
props: ['propsdata'],
//5. template 속성
template: '<p>{{ propsdata }}</p>'
});
//1. 뷰 인스턴스 생성
new Vue({
el: '#app',
data: {
message : 'Hello Vue! passed from Parent Component'
}
});
</script>
</body>
</htlml>

위의 코드에서 child-component를 전역으로 등록한 것 이외에 딱히 상위 컴포넌트를 지정하지 않았습니다.
그럼에도 불구하고 뷰 인스턴스 안에 마치 상위 컴포넌트가 존재하는 것 처럼 하위 컴포넌트로 props를 내려보냈습니다.
그 이유는 컴포넌트를 등록함과 동시에 뷰 인스턴스 자체가 상위 컴포넌트가 되기 때문입니다.
뷰 인스턴스(상위컴포넌트) child-component(하위컴포넌트) |
즉, 인스턴스에 새로운 컴포넌트를 등록하면 기존에 있는 컴포넌트가 상위 컴포넌트가 되고, 새로 등록된 컴포넌트는 하위 컴포넌트가 됩니다.
이때 뷰 인스턴스를 최상위 컴포넌트(root component)라고 부릅니다.
하위에서 상위 컴포넌트로 이벤트 전달하기
하위 컴포넌트에서 상위 컴포넌트로의 통신은 이벤트를 발생시켜(event emit) 상위 컴포넌트에 신호를 보내면 됩니다.
상위 컴포넌트는 하위 컴포넌트의 특정 이벤트가 발생하기를 기다리고 있다가 하위 컴포넌트에서 특정 이벤트가 발생하면 상위 컴포넌트에서 해당 이벤트를 수신하여 상위 컴포넌트의 메서드를 호출하는 것입니다.
하위에서 상위 컴포넌트로 데이터를 전달할 수는 없는가?
뷰 공식 사이트에서는 해당 방법을 다루지 않습니다. 뷰의 단방향 데이터 흐름에 어긋나는 구현 방법이기 때문입니다. 하지만 복잡한 뷰 애플리케이션을 구축해야할 때 이벤트 버스(event bus)를 이용하여 데이터를 전달할 경우도 있습니다. 이는 뒤에서 다루도록 하겠습니다 ^^..
이벤트 발생과 이벤트 수신(emit과 v-on 속성)
//이벤트 발생
this.$emit('이벤트명');
<!--이벤트 수신-->
<child-component v-on:하위컴포넌트에서-발생한-이벤트명="상위컴포넌트의 메서드명"></child-component>
$emit()을 호출하는 위치는 하위 컴포넌트의 특정 메서드 부분이므로 this는 하위 컴포넌트를 가리킵니다.
예제3
예제3
<htlml>
<head>
<title>뷰 컴포넌트 통신</title>
</head>
<body>
<div id="app">
<!--3. 최상위컴포넌트의 메서드 printText()실행-->
<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',{
//1. show버튼 클릭->showLog호출
template: '<button v-on:click="showLog">show</button>',
//2. showLog호출 show-log이벤트 발생
methods: {
showLog : function(){
this.$emit('show-log');
}
}
});
//뷰 인스턴스 생성
new Vue({
el: '#app',
data: {
message : 'Hello Vue! passed from Parent Component'
},
methods: {
//4. 콘솔 로그 출력
printText: function(){
console.log("이벤트 받았다!!");
}
}
});
</script>
</body>
</htlml>

show 버튼을 눌렀을때 printText()메서드가 실행되는 예제이다.
같은 레벨의 컴포넌트 간 통신
상위컴포넌트 | ||
/\ 2 | | 1 \/ |
2 | \/ |
|
하위컴포넌트 A | <--x--> | 하위컴포넌트B |
뷰는 상위에서 하위로 데이터 전달하는 기본 통신규칙을 따르기 때문에 하위컴포넌트 A와 B 간의 통신은 상위컴포넌트를 통한다.
하위 컴포넌트 A에서 공통 상위 컴포넌트로 이벤트를 전달한 후 공통 상위 컴포넌트에서 2개의 하위 컴포넌트에 props를 내려보내야한다.
이 방식은 상위 컴포넌트가 필요 없는 경우에도 같은 레벨 간에 통신하기 위해 강제로 상위 컴포넌트를 두어야 한다. 이를 해결할 수 있는 방법이 이벤트 버스이다.
관계없는 컴포넌트 간 통신 - 이벤트 버스
이벤트 버스는 개발자가 지정한 2개의 컴포넌트 간에 데이터를 주고받을 수 있는 방법이다.
최상위 컴포넌트 | |
| \/ |
/\ | |
상위 컴포넌트A | 상위 컴포넌트B |
| \/ |
/\ | |
하위 컴포넌트A | 하위 컴포넌트B |
하위컴포넌트 B에서 상위 컴포넌트 A로 데이터를 전달하기 위해서 원래는 위의 그림과 같은 과정을 통해야 했지만 이벤트 버스를 이용하면 바로 데이터를 전달할 수 있어 편리하다.
//이벤트 버스 정의를 위한 추가 인스턴스 1개 생성
var eventBus = new Vue();
//이벤트를 보내는 컴포넌트
methods: {
메서드명 : function(){
eventBus.$emit('이벤트명',데이터);
}
}
//이벤트 받는 컴포넌트
methods: {
created : function(){
eventBus.$on('이벤트명',function(데이터){...});
}
}
예제4
예제4
<htlml>
<head>
<title>뷰 컴포넌트 통신</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();
Vue.component('child-component',{
template: '<div>하위 컴포넌트 영역입니다.<button v-on:click="showLog">show</button></div>',
methods: {
showLog : function(){
eventBus.$emit('triggerEventBus', 100);
}
}
});
//뷰 인스턴스 생성
new Vue({
el: '#app',
created : function(){
eventBus.$on('triggerEventBus', function(value){
console.log("이벤트를 전달받음. 전달받은 값 : ", value);
})
}
});
</script>
</body>
</htlml>

'Front' 카테고리의 다른 글
[Vue.js]뷰 라우터 (0) | 2023.07.31 |
---|---|
[Vue]전역 인스턴스와 지역 인스턴스 (0) | 2023.06.11 |
[Vue]뷰 인스턴스 생성 (0) | 2023.05.22 |
[Vue]맥북 Vue 실습 환경설정 하기 (0) | 2023.04.06 |