Framework/Vue.js

[Vue.js] Vue.js 기본 - Component 통신

꽁치_로그 2022. 7. 24. 22:29

Component 통신 방식 - 부모 / 자식 레벨


Vue Component는 각각 고유한 데이터 유효 범위를 갖습니다. 따라서 Component 간에 데이터를 주고 받기 위해서는 아래와 같은 규칙을 따라야 합니다.

자식 Component → 부모 Component : Event 발생
부모 Component → 자식 Component : Props 전달

즉, 자식 Component는 부모 Component에게 Event를 발생시켜 올려줌으로써, 부모 Component는 자식 Component에게 props 속성을 통해 데이터를 전달하게 됩니다.

부모, 자식 Component 통신

 

Props

<Component v-bind : 'props 속성 이름' = "부모 Component의 데이터 이름"> </Component>

부모 Component → 자식 Component

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">    
    <!-- <app-header v-bind:프롭스 속성 이름 = "상위 컴포넌트의 데이터 이름"></app-header> -->
    <app-header v-bind:propsdata = "message"></app-header>
    <app-content v-bind:propsdata = "num"></app-content>
  </div>

  <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
  <script>
    var appHeader = {
      template: '<h1>{{propsdata}}</h1>',
      props: ['propsdata']
    }

    var appContent ={
      template: '<div>{{propsdata}}</div>',
      props: ['propsdata'] 
      // Component는 고유의 데이터 유효 범위를 갖기 때문에, props 명 동일하게 해도 상관 없다.
    }

    // 인스턴스 생성 : 상위 컴포넌트
    new Vue({
      el: '#app',      
      components: {
        // 하위 컴포넌트
        'app-header': appHeader,
        'app-content': appContent
      },
      data:{
        message: 'hi',
        num: 10
      }
    })
    // 상위 컴포넌트 data 변경시 --> props에 의해 하위 컴포넌트 속성 변경
  </script>

</body>
</html>

위의 예제를 쪼개어 본다면 아래와 같습니다.

1. 부모 Component와 자식 Component를 등록해줍니다.

// 인스턴스 생성 : 상위 컴포넌트
    new Vue({
      el: '#app',      
      components: {
        // 하위 컴포넌트
        'app-header': appHeader,
        'app-content': appContent
      },
      data:{
        message: 'hi',
        num: 10
      }
    })

2. 자식 Component에 해당하는 속성을 정의합니다. template에 'propdsdata'를 바인딩 해줍니다.

    var appHeader = {
      template: '<h1>{{propsdata}}</h1>',
      props: ['propsdata']
    }

    var appContent ={
      template: '<div>{{propsdata}}</div>',
      props: ['propsdata'] 
      // Component는 고유의 데이터 유효 범위를 갖기 때문에, props 명 동일하게 해도 상관 없다.
    }

3. 부모 Component 내 자식 Component( 'app-header', 'app-content')를 선언합니다. 

  <div id="app">    
    <!-- <app-header v-bind:프롭스 속성 이름 = "상위 컴포넌트의 데이터 이름"></app-header> -->
    <app-header v-bind:propsdata = "message"></app-header>
    <app-content v-bind:propsdata = "num"></app-content>
  </div>

결과적으로 자식 Component('app-header',  'app-content')부모 Component('app'로부터 각각 "message", "num"의 데이터를 받게되어 template에 뿌려지게 됩니다.

 

Event

<Component v-on: '자식 Component에서 발생한 Event 이름' = "부모 Component의 Method 이름"> </Component>

자식 Component → 부모 Component

Event를 이용한 예제는 아래와 같습니다.

!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">
    <!--<app-header v-on:하위 컴포넌트에서 발생한 이벤트 이름 = "상위 컴포넌트의 메서드 이름" ></app-header>-->
    <!--하위 컴포넌트(app-header) Event(pass) 발생시, 상위 컴포넌트(new Vue())의 logText Method 실행-->
    <app-header v-on:pass="logText"></app-header> 
    <app-content v-on:increase="increaseNum"></app-content>
    <p>{{num}}</p>
  </div>

  <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
  <script>
    var appHeader = {
      // button Click 시, passEvent Method에 의해 하위 컴포넌트 Event('pass') 발생
      template: '<button v-on:click="passEvent">click me</button>',
      methods: {
        passEvent: function(){          
          this.$emit('pass');
        }
      },
    }
    var appContent = {
      template: '<button v-on:click="addNumber">add</button>',
      methods:{
        addNumber: function(){
          this.$emit('increase');          
        }
      }
    }

    new Vue({
      el: '#app',
      // 하위 컴포넌트
      components:{
        'app-header': appHeader,
        'app-content': appContent
      },
      methods:{
        logText: function(){
          console.log('hi');
        },
        increaseNum: function(){
          this.num += 1;
          console.log(this.num);
        }
      },
      data:{
        num: 10
      }
    });
  </script>
</body>
</html>

위의 예제를 쪼개어 본다면 아래와 같습니다.

1. 부모 Component와 자식 Component를 등록해줍니다. 이때 생성자의 옵션들을 추가해줍니다.

  new Vue({
      el: '#app',
      // 하위 컴포넌트
      components:{
        'app-header': appHeader,
        'app-content': appContent
      },
      methods:{
        logText: function(){
          console.log('hi');
        },
        increaseNum: function(){
          this.num += 1;
          console.log(this.num);
        }
      },
      data:{
        num: 10
      }
    });

2. 자식 Component에 해당하는 속성을 정의합니다. 자식 Component에서 button을 클릭할 경우 각각 "passEvent""addNumber" 메소드가 실행되고 이로인해 'pass', 'increase' Event가 발생하게 됩니다.

    var appHeader = {
      // button Click 시, passEvent Method에 의해 하위 컴포넌트 Event('pass') 발생
      template: '<button v-on:click="passEvent">click me</button>',
      methods: {
        passEvent: function(){          
          this.$emit('pass');
        }
      },
    }
    var appContent = {
      template: '<button v-on:click="addNumber">add</button>',
      methods:{
        addNumber: function(){
          this.$emit('increase');          
        }
      }
    }

3. 부모 Component 내 자식 Component( 'app-header', 'app-content')를 선언합니다. 자식 Component에서 'pass', 'increase' Event가 발생시 v-on에 의해 "logText", "increaseNum" 메소드가 실행됩니다.

  <div id="app">
    <!--<app-header v-on:하위 컴포넌트에서 발생한 이벤트 이름 = "상위 컴포넌트의 메서드 이름" ></app-header>-->
    <!--하위 컴포넌트(app-header) Event(pass) 발생시, 상위 컴포넌트(new Vue())의 logText Method 실행-->
    <app-header v-on:pass="logText"></app-header> 
    <app-content v-on:increase="increaseNum"></app-content>
    <p>{{num}}</p>
  </div>

결과적으로

2. 자식 Component('app-header', 'appContent')의 각각의 버튼을 클릭할경우 "passEvent", "addNumber" 메소드가 실행되고 'pass', 'increase'의 Event가 발생하게 됩니다.

1. 3. 이로인해 부모 Component의 "logText", "increaseNum" 메소드가 실행되게 됩니다.

이처럼 자식 Component에서 부모 Component의 데이터 전달은 Event 발생에 의해 이뤄지는것을 확인할 수 있었습니다.

 

Component 통신 방식 - 같은 레벨


동일한 부모 Component를 가진 자식 Component 간의 통신은 Event와 Props를 활용하여 이루어집니다.

자식 Component → 부모 Component → 자식 Component 

 자식 Component → 부모 Coponent
<Component v-on: '자식 Component에서 발생한 Event 이름' = "부모 Component의 Method 이름"> </Component>

 부모 Component → 자식 Coponent
<Component v-bind: 'props 속성 이름' = "부모 Component의 데이터 이름"> </Component>
<!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">
    <!-- <app-header v-bind:props 속성이름="상위 컴포넌트의 데이터 이름"></app-header> --> 
    <app-header v-bind:propsdata="num"></app-header>
    <!--상위 컴포넌트로 이벤트(pass) 발생을 통해 데이터 전달(deliverNum)--> 
    <app-content v-on:pass="deliverNum"></app-content>
  </div>

  <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>  
  <script>
    var appHeader = {
      template: '<div>header</div>',
      props: ['propsdata']
    }
    // 하위 컴포넌트 -> 상위 컴포넌트 : event('pass') 발생
    var appContent = {
      template: '<div>content<button v-on:click="passNum">pass</button></div>',
      methods: {
        passNum: function(){
          this.$emit('pass', 10);
        }
      },
    }

// 상위 컴포넌트
    new Vue({
      el: '#app',
// 하위 컴포넌트
      components: {
        'app-header': appHeader,
        'app-content': appContent
      },
      data:{
        num: 0
      },
      methods:{
        deliverNum: function(value){
          this.num = value;
        }
      }

    })
  </script>

</body>
</html>
반응형