본문 바로가기

JavaScript/Vue.js

[Do it! Vue.js 입문] 05. 뷰 상위-하위 컴포넌트 간의 통신

반응형

컴포넌트 간 통신과 유효 범위

Vue.js는 컴포넌트로 화면을 구성한다.

 

각 컴포넌트마다 자체적으로 고유한 유효 범위(Scope)를 갖고 있고, 때문에 같은 웹 페이지라도 데이터를 공유할 수 없다. 이는 뷰 프레임 워크 내부적으로 정의된 특징으로, 각 컴포넌트의 유효 범위가 독립적이기 때문에 다른 컴포넌트의 값을 직접적으로 참조할 수 없다.

 

 

#예제 1

<html>
  <head>
    <title>Vue sample</title>
  </head>
  <body>
    <div id="app">
      <h3>app 영역</h3>
      <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>

 

cmp1과 cmp2 지역 컴포넌트를 등록하고, cmp2 컴포넌트에서 cmp1 컴포넌트의 data.cmp1Data 값을 직접 참조했을 때, 값이 나오지 않는걸 확인할 수 있다.

 

상위 컴포넌트와 하위 컴포넌트

앞서 [Do it! Vue.js 입문] 04. 뷰 컴포넌트에서 다룬 컴포넌트 등록 방법으로 지역, 전역 컴포넌트를 등록하면 자연스럽게 하위 컴포넌트가 되고고 하위 컴포넌트를 등록한 인스턴스는 상위 컴포넌트가 된다.

 

 

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

 

하위 컴포넌트의 props 속성 정의 방식

Vue.component('컴포넌트 이름', {
	props: ['props 속성 이름']
});

상위 컴포넌트 HTML 코드

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

 

#예제 2

뷰 인스턴스의 data 속성에 정의된 message 속성을 하위 컴포넌트에 props로 전달하여 화면에 나타내는 코드이다.

<html>
  <head>
    <title>Vue sample</title>
  </head>
  <body>
    <div id="app">
      <!-- 팁 : 오른쪽에서 왼쪽으로 속성을 읽으면 더 수월합니다. ex) message를 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>

      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>

 

코드를 살펴보자면,

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

2. Vue.component()로 하위 컴포넌트인 child-component를 등록

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

4. HTML에 컴포넌트 태그를 추가.

   v-bind:propsdata="message"는 상위 컴포넌트의 message 속성 값을 하위 컴포넌트의 propsdata로 전달.

5. child-component의 propsdata에 message값이 전달되었으니, 

   최종적으로 template: '<p>{{ propsdata}}</p>'는 '<p>Hello Vue! passed from Parent component</p>'이 됨

 

 

 

인스턴스에 새로운 컴포넌트를 등록하면 기존에 있는 컴포넌트는 상위 컴포넌트(부모)가 되고, 새로 등록된 컴포넌트는 하위(자식) 컴포넌트가 된다. 이렇게 새 컴포넌트를 등록한 인스턴스를 최상위 컴포넌트(Root Component)라고도 부른다.

 

(* 하위에서 상위 컴포넌트로 데이터를 전달은 뷰의 단방향 데이터 흐름에 어긋나는 구현 방법으로 뷰 공식 사이트에서 따로 방법을 다루지 않는다. 다만 복작합 뷰 애플리케이션을 구축할 때 이벤트 버스(Event Bus)를 이용해 데이터를 전달하는 방식을 사용한다. 추후 이벤트 버스에 대해 다룰때 언급)

 

 


하위에서 상위 컴포넌트로 이벤트 전달하기

하위에서 상위 컴포넌트로 통신을 할 때는 이벤트를 발생(event emit)시켜 상위 컴포넌트에 신호를 보낸다.

상위 컴포넌트에서 하위 컴포넌트의 특정 이벤트가 발생하기를 기다리고 있다가, 이벤트가 발생하면 해당 이벤트를 수신하여 상위 컴포넌트의 메서드를 호출한다.

 

<!-- 이벤트 발생,  $emit()을 이용한 이벤트 발생 -->
this.$emit('이벤트명');

<!-- 이벤트 수신,  v-on : 속성을 이용한 이벤트 수신 -->
<child-component v-on:이벤트명="상위 컴포넌트의 메서드명"></child-component>

 

이벤트명에 입력한 특정 이벤트가 발생하면, 상위 컴포넌트의 메서드명에 입력한 메서드가 실행되고,

$emit()가 호출되면 괄호 안에 정의된 이벤트가 발생한다.

 

 

#예제 3

child-component의 show 버튼을 클릭하여 이벤트를 발생시키고(클릭 이벤트), 발생한 이벤트로 상위 컴포넌트(여기선 루트 컴포넌트)의 printText() 메서드를 실행시킨다.

<html>
  <head>
    <title>Vue sample</title>
  </head>
  <body>
    <div id="app">
      <child-component v-on:show-log="printText"></child-component>
      <!-- show-log 하위 컴포넌트의 이벤트 명, printText 상위 컴포넌트의 메서드명 -->
    </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'); // 이벤트 발생 로직
          }
        }
      });

      var app = new Vue({
        el:'#app',
        data: {
          message : 'Hello Vue! passed from Parent component'
        },
        methods: {
          printText: function() {
            console.log("received an event");
          }
        }
      });

    </script>
  </body>
</html>

 

1. show 버튼을 클릭하면 클릭 이벤트 v-on:click="showLog"에 따라 showLog() 메서드가 실행

2. this.$emit('show-log')을 호출하면 괄호 안에 정의된 show-log 이벤트가 발생

3. v-on:show-log의 대상 메서드인 최상위 컴포넌트의 메서드 printText()가 실행

4. printText()가 실행되면서 콘솔에 로그 received an event가 출력

 

 

 

 

 

 

반응형