본문 바로가기
Programming/Vue

[Vue] 컴포넌트의 통신 방식 ( Props, Emit )

by 공부합시다홍아 2024. 6. 25.
 

[Vue] 템플릿 문법과 컴포넌트(component)

[Vue] Vue & 인스턴스Vuevue는 웹 애플리케이션의 사용자 인터페이스를 만들기 위해 사용하는 오픈 소스 프로그레시브 JS 프레임워크이다.  Vue.jsVue.js - The Progressive JavaScript Frameworkvuejs.orgVue의 핵심

hong-study.tistory.com


컴포넌트의 통신 방식

뷰 컴포넌트는 각 각 고유한 데이터 유효 범위를 갖는다. 따라서, 컴포넌트 간에 데이터를 주고 받기 위해선 아래와 같은 규칙을 따라야 한다.

  • 상위에서 하위로 데이터 전달 : Props 속성
  • 하위에서 상위로 이벤트 전달 : 이벤트 발생

Props 속성

프롭스 속성은 컴포넌트 간에 데이터를 전달할 수 있는 컴포넌트 통신 방법 중 하나이다. 속성을 기억할 때는 상위 컴포넌트에서 하위 컴포넌트로 내려보내는 데이터 속성으로 기억하면 쉽다.

프롭스 속성을 이용할 때는 "디렉티브"를 이용하여, 상/하위 컴포넌트 모두에 각 각 코드를 추가해줘야 한다.

<body>
    <div id="app">
        <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"]
        }

        new Vue({
            el: "#app",
            components:{
                "app-header" : appHeader,
                "app-content" : appContent
            },
            data:{
                message : "hi",
                num: 10
            }
        });
    </script>
</body>

해당 구문은 두 개의 컴포넌트로 구성되어 있고, 각 각의 컴포넌트는 서로 다른 Props를 가진다.
이전에 JS에 관해 공부를 할 때 SCOPE라는 개념에 대해 이해를 했다. 컴포넌트도 스코프의 개념과 동일하게
서로 영향을 주지 않아, 내부 Props의 명칭을 동일하게 주고 사용해도 영향을 주지 않는다. 
단, bind 할 대상이 ID / CLASS일 경우 Data 속성의 값을 설정할 때는 주의를 해야한다. 스타일 속성이나 스크립트 기능의 중복의 우려가 있다.

각 컴포넌트에 대한 props 명을 받아, vue 속성의 값을 따로 받으면 아래와 같이 값을 출력한다.

전체 root 가 가지고 있는 data 속성의 값

app-header 컴포넌트가 가지고 있는 데이터 ( propsdata로 message 값이 할당 )

app-content 컴포넌트가 가지고 있는 데이터 ( propsdata로 num 값이 할당 )


Event Emit

앞서 컴포넌트의 통신 방식은 상위에서 하위로, 하위에서 상위로 전달하는 방식이 있다. Event Emit은 하위에서 상위로 이벤트를 전달하는 방식이다.

이벤트 발생 코드 형식

Event Emit 도 Props 방식과 동일하게 상위 / 하위 모두 코드를 작성해줘야 한다.

// 하위 컴포넌트의 내용
this.$emit('이벤트 명');
<!-- 상위 컴포넌트의 템플릿 -->
<div id="app">
  <child-component v-on:이벤트 명="상위 컴포넌트의 실행할 메서드 명 또는 연산"></child-component>
</div>

props의 경우는 v-bind를 사용했지만, emit의 경우는 v-on을 사용하여 이벤트 명을 지정한다.

<div id="app">
    <p>{{num}}</p>
    <app-header v-on:pass="logText"></app-header>
    <app-content v-on:increase="increaseNumber"></app-content>
</div>

HTML 파일의 예시이다. 해당 예시는 NUM이라는 초기 값에 pass를 누르면 하위와 상위 가 어떤 순서로 출력되는지에 대해  console에 출력하고, increase 는 num을 1씩 증가시킨다.
그리고 아래는 뷰 인스턴스이다. 

new Vue({
    el: "#app",
    components : {
        "app-header" : appHeader,
        "app-content" : appContent
    },
    methods : {
        logText : function(){
            console.log("상위 컴포넌트 실행");
        },
        increaseNumber : function(){
            this.num = this.num + 1;
        }
    },
    data : {
        num : 10
    }
});
 <script>

        var appHeader = {
            template : "<button v-on:click='passEvent'>click me</button>",
            methods:{
                passEvent : function(){
                    this.$emit("pass");
                    console.log("하위 컴포넌트 실행");
                }
            }
        }

        var appContent = {
            template : "<button v-on:click='addNumber'>add</button>",
            methods : {
                addNumber : function(){
                    this.$emit("increase");
                    console.log("increase 실행");
                }
            },
            props : ["propsNum"]
        }

        new Vue({
            el: "#app",
            components : {
                "app-header" : appHeader,
                "app-content" : appContent
            },
            methods : {
                logText : function(){
                    console.log("상위 컴포넌트 실행");
                },
                increaseNumber : function(){
                    this.num = this.num + 1;
                }
            },
            data : {
                num : 10
            }
        });
    </script>

스크립트 구문의 경우 2개의 컴포넌트, app-header와 app-content로 구성되어 있다.

app-header

var appHeader = {
    template : "<button v-on:click='passEvent'>click me</button>",
    methods:{
        passEvent : function(){
            this.$emit("pass");
            console.log("하위 컴포넌트 실행");
        }
    }
}

appHeader 컴포넌트의 구성을 template에 button에 passEvent가 설정되어 있다.
passEvent의 경우, appHeader 컴포넌트 내부 속성인 methods 부분에서 설정이 가능하다.
이때 this(=appHeader)의 $emit을 사용하여 이벤트의 이름을 "pass" 라고 지정한다.

이렇게 구성된 pass 이벤트명을 위 app-header 태그의 v-on에서 pass로 받아 사용한다.
대상 이벤트는 app-header 컴포넌트를 지정하는 app Header 내에 지정됐기 때문에
app-content에서 사용하면 사용이 되지 않는다.

app-content

var appContent = {
    template : "<button v-on:click='addNumber'>add</button>",
    methods : {
        addNumber : function(){
            this.$emit("increase");
            console.log("increase 실행");
        }
    },
    props : ["propsNum"]
}

appContent 컴포넌트의 경우에도 app-header와 비슷하게 구성되어 있다.

그리고 위를 보면 vue 인스턴스에 내의 메소드가를 통해 각 각의 컴포넌트에서 메서드를 따로 따로 실행시킨다.

app-header가 실행됐을 경우
app-content 가 실행할 경우 increase 된 만큼 카운트가 증가한다.

 

728x90

'Programming > Vue' 카테고리의 다른 글

[Vue] 라우터 ( Router )  (0) 2024.06.25
[Vue] 템플릿 문법과 컴포넌트(component)  (0) 2024.06.25
[Vue] Vue & 인스턴스  (0) 2024.06.25