Vue.js

[Vue.js] 뷰 scope | 데이터 주고 받는 방법 (props, emit, on, eventBus)

솔솔 2021. 9. 7. 10:49
반응형

1. 뷰의 스코프(범위)

뷰의 경우 컴포넌트로 화면을 구성하므로 같은 웹 페이지라도 데이터를 공유할 수 없다.

그 이유는 컴포넌트마다 자체적으로 고유한 유효 범위를 갖기 때문이다.

뷰는 각 컴포넌트의 유효 범위가 독립적이기 때문에 다른 컴포넌트의 값을 직접적으로 참조할 수 없다.

 

쉽게 예제로 이해해보면

<div id="app">
  <my-component1></my-component1>
  <my-component2></my-component2>
</div>

my-component1, my-component2 2개의 컴포넌트를 등록하고 아래서 세팅해주었다.

    <script>
      //첫번째 컴포넌트
      const cmp1 = {
        template : '<div>첫 번째 지역 컴포넌트 : {{ cmp1Data }}</div>',
        data : function(){
          return {
            cmp1Data : 100
          }
        }
      };

      //2번째 컴포넌트
      const cmp2 = {
        template : '<div>두 번째 지역 컴포넌트 : {{ cmp2Data }}</div>',
        data : function(){
          return {
            cmp2Data : cmp1.data.cmp1Data
          }
        }
      };

      new Vue({
        el : '#app',
        components : {
          'my-component1' : cmp1,
          'my-component2' : cmp2
        }
      });
    </script>

첫번째 컴포넌트는 자신의 값을 가지고 세팅하였고, 두번째 컴포넌트 return 값은 첫번째 컴포넌트 값을 참조하였다.

출력해보면 결과는 첫번째 컴포넌트 값을 참조하였던 두번째 컴포넌트 값은 빈 값이다. 이유는 컴포넌트의 scope 때문에 my-component2 에서 my-component1을 직접 참조할 수 없기 때문이다.

 

2. 데이터 주고 받기

1) props 속성

- 상위 컴포넌트에서 하위 컴포넌트로 데이터를 전달할 때 사용하는 속성

  * 뷰에서 상위 컴포넌트와 하위 컴포넌트의 개념??

   -> 이는 컴포넌트를 등록함과 동시에 뷰 인스턴스 자체가 상위 컴포넌트가 되기 때문

       즉, 기존에 있는 인스턴스에 새로운 컴포넌트를 등록하면 기존에 컴포넌트는 상위 컴포넌트가 되고,

       새로 등록된 컴포넌트는 하위 컴포넌트가 된다. 이렇게 새 컴포넌트를 등록한 인스턴스를 최상위 컴포넌트 즉, root component 라고 한다.

<child-component v-bind:props 속성 이름="상위 컴포넌트의 data 속성"></child-component>

Vue.component('child-component', {
	props: ['props 속성 이름']
});

하단 소스 참조하여 처리되는 순서

  1. new Vue()로 인스턴스 하나 생성

  2. Vue.component()를 이용하여 child-component 등록

  3. child-component의 내용에 props 속성으로 propsdata를 정의

  4. <child-component> 태그의 v-bind 속성을 보면 v-bind:propsdata="message" 상위 컴포넌트의 message 속성 값 'Hello Vue!' 텍스트를 하위 컴포넌트인 propsdata로 전달

  5. {{ propsdata }} 는 위에서 넘겨받은 값은 'Hello Vue!'로 치환

<div id="app">
	// 4
	<child-component v-bind:propsdata="message"></child-component>
</div>

<script>
	// 2
	Vue.component('child-component', {
    	// 3
    	props : ['propsdata'],
        // 5
        template : '<p> {{ propsdata }}</p>'
    });
    
    // 1
    new Vue({
    	el : '#app',
        data : {
        	message : 'Hello Vue!'
        }
    });
</script>

결론 : 뷰 인스턴스의 data 속성에 정의된 message 속성값을 하위 컴포넌트에 props로 전달

 

2) 이벤트 발생과 수신

props는 상위에서 하위 컴포넌트로 데이터를 전달하는 방식이었다면, $emit()은 이벤트를 발생시켜 상위 컴포넌트에 신호를 보내는 속성

- $emit() : 이벤트 발생 속성

- v-on: : 이벤트 수신 속성

// 이벤트 발생
this.$emit('이벤트명');

// 이벤트 수신
<child-component v-on:이벤트명="상위 컴포넌트의 메서드명"></child-component>

이벤트 발생시킬 때의 this는 하위 컴포넌트를 가르킨다.

 

하단 소스 참조하여 처리되는 순서

  1. [show] 버튼 클릭하면 클릭이벤트 v-on:click="showLog"에 따라 showLog() 실행

  2. showLog() 메서드 안에 this.$emit('show-log') 실행되면서 show-log 이벤트 발생

  3. show-log 이벤트는 <child-component>에 정의한 v-on:show-log에 전달되고, v-on:show-log의 대상 메서드인 최상위 컴포넌트의 메서드 printText() 실행

  4. printText() 메서드 안에 console.log 내용인 'received an event' 출력

<div id="app">
	// 3
	<child-component v-on:show-log="printText"></child-component>
</div>

<script>
	Vue.component('child-component', {
    	// 1
    	template : '<button v-on:click="showLog">show</button>',
        // 2
        methods: {
        	showLog : function(){
            	this.$emit('show-log');
            }
        }
    });
    
    const app = new Vue({
    	el : '#app',
        data : {
        	message : 'Hello, Vue'
        },
        methods : {
        	// 4
        	printText : function(){
            	console.log("received an event");
            }
        }
    });
</script>

결론 : .$emit()으로 이벤트를 발생시키고, v-on으로 이벤트를 받는다.

 

3) 이벤트 버스 (EventBus)

1), 2) 에서는 상.하위 컴포넌트 간의 데이터 주고받기 내용이었다면, 이벤트 버스는 관계없는 컴포넌트 간의 통신을 말한다.

- .$emit() : 이벤트 발생 속성

- .$on() : 이벤트 수신 속성

// 이벤트 버스를 위한 추가 인스턴스 1개 생성
var eventBus = new Vue();

// 이벤트를 보내는 컴포넌트
methods: {
	메서드명 : function(){
    	eventBus.$emit('이벤트명', 데이터);
    }
}

// 이벤트를 받는 컴포넌트
methods: {
	created : function(){
    	eventBus.$on('이벤트명', function( 데이터 ){
        
        });
    }
}

하단 소스 참조하여 처리되는 순서

  1. 먼저 이벤트 버스로 활용할 새 인스턴스를 1개 생성하고 eventBus라는 변수에 참조한다. 이제 eventBus변수로 새 인스턴스의 속성과 메서드에 접근 가능

  2. template 속성에는 '하위 컴포넌트 영역입니다. 라는 텍스트와 [show] 버튼을 추가.

  3. methods 속성에는 showLog() 메서드 정의하고, 메서드 안에는 eventBus.$emit()을 선언.

     triggerEventBus라는 이벤트를 발생하는 로직을 추가하고, 이벤트가 발생할 때 수신하는 쪽에 100이라는 값을 함께 전달

  4. 상위 컴포넌트의 created 라이프 사이클 훅에 eventBus.$on()으로 이벤트를 받는 로직을 선언

     발생한 이벤트 triggerEventBus를 수신할 때 value로 앞에서 전달되는 인자 값 100을 받아 콘솔에 출력

<div id="app">
	<child-component></child-component>
</div>

<script>
	// 1
	var eventBus = new Vue();
    
    Vue.component('child-component', {
    	// 2
    	template : '<div>하위 컴포넌트 영역입니다. <button v-on:click="showLog">show</button></div>',
        // 3
        methods : {
        	showLog : function(){
        		eventBus.$emit('triggerEventBus', 100);
            }
        }
    });
    
    var app = new Vue ({
    	el : '#app',
        created : function(){
        	// 4
        	eventBus.$on('triggerEventBus', function(value){
            	console.log("이벤트를 전달받음. 전달받은 값 : ", value);
            });
        }
    });
</script>

 

 

* Do it! Vue.js 입문 책으로 공부하며 작성하는 글로 잘못된 정보가 있을 경우 댓글 달아주시면 감사하겠습니다 : )

반응형