FE/vue

3. 뷰 컴포넌트 통신

ppagi 2019. 7. 4. 18:17

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을 여러 컴포넌트에서 정의하면 동시에 데이터를 받는건지?