Web/FrontEnd

[Vue.js] 상위 컴포넌트, 하위 컴포넌트, 같은 레벨 컴포넌트

감싹이 2022. 11. 16. 08:50

컴포넌트는 각각 고유한 유효 범위를 가지고 있으므로 직접 다른 컴포넌트의 값을 참조할 수 없다. 

따라서 뷰에서 정의한 방법을 따라야 하는데, 가장 기본적인 데이터 전달 방법은 상위-하위 컴포넌트 간의 데이터 전달 방법이다.

 

😊 1. 상위 컴포넌트 -> 하위 컴포넌트

props 속성 : 상위 컴포넌트에서 하위 컴포넌트로 데이터를 전달할 때 사용하는 속성
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<body>
  <div id="app">
    <child-component v-bind:propsdata="message"></child-component>
  </div>

  <script src="https://cdn.jsdelivr.net/npm/vue@2.7.13/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>

예제 코드에서 child-component를 전역으로 등록한 것 외에 딱히 상위 컴포넌트를 지정하지 않았으나 마치 컴포넌트 안에 상위 컴포넌트가 존재하는 것처럼 하위 컴포넌트로 props를 내려보냈다.

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

 

😊😊 2. 하위 컴포넌트 -> 상위 컴포넌트

하위 컴포넌트에서 상위 컴포넌트로의 통신은 이벤트를 발생시켜 상위 컴포넌트에 신호를 보내면 된다.

 

$emit() : 괄호 안에 정의된 이벤트 발생
               $emit()을 호출할 때 사용하는 this는 하위 컴포넌트를 가리킴
v-on : 호출한 이벤트를 받는 디렉티브. 하위 컴포넌트를 등록
<!DOCTYPE html>
<html lang="ko">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</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.7.13/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("receieved an event")
    }
  }
})

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

v-on:click="showLog"에 따라 'showLog' methods가 실행

 

 

😊😊😊 3. 같은 레벨 컴포넌트

뷰는 상위에서 하위로만 데이터를 전달해야 하는 기본적인 통신규칙을 따르므로 같은 레벨 컴포넌트에 정보를 전달하기 위해서는 하위 컴포넌트에서 공통상위 컴포넌트로 이벤트를 전달한 후 공통 상위 컴포넌트가 하위 컴포넌트에 다시 props를 주는 방식을 이용해야 한다.

 

하지만 이런 통신 구조는 상위 컴포넌트가 필요 없음에도 강제로 상위 컴포넌트를 두어야 하기 때문에 이벤트 버스를 활용한다.

<!DOCTYPE html>
<html lang="ko">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<body>
  <div id="app">
    <child-component></child-component>
  </div>

  <script src="https://cdn.jsdelivr.net/npm/vue@2.7.13/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)
        }
      }
    })

    var app = new Vue({
      el: '#app',
      created: function(){
        eventBus.$on('triggerEventBus', function(value){
          console.log("이벤트를 전달받음. 전달받은 값 : ", value)
        })
      }
    })
  </script>
</body>
</html>

이벤트 버스를 활용하면 props 속성을 이용하지 않고도 원하는 컴포넌트에 정보를 전달할 수 있어 편리하지만 컴포넌트가 많아지면 어디서 어디로 보냈는지 관리가 되지 않는다

=> Vuex(상태관리도구) 필요