Vue.js props, emit 개념 정확하게 잡기

찬찬잉·2022년 1월 11일
1

Vue.js

목록 보기
10/14
post-thumbnail

뷰 컴포넌트 통신

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

vue의 경우 컴포넌트로 화면을 구성하므로 같은 웹 페이지라도 데이터를 공유할 수 없습니다.
그 이유는 컴포넌트마다 자체적으로 고유한 유효 범유 (scope)를 갖기 때문입니다.

이는 뷰 프레임워크 내부적으로 정의된 특징입니다.

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

<div id="app">
	<my-component1></my-component1>
    <my-component2></my-component2>
<div>
<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>

출력하게 되면 아래와 같은 화면이 나오게 된다.

이렇게 된 이유는 my-component2에서 my-component1의 값을 직접 참조할 수 없기 때문입니다.

이런 이유때문에 상위(부모) - 하위(자식) 컴포넌트간에 데이터 전달 방식이 존재합니다.

상위 - 하위 컴포넌트란 트리 구조에서 부모 노드, 자식 노드처럼 컴포넌트 간의 관계가 부모, 자식으로 이루어진 컴포넌트를 의미합니다.

먼저 상위에서 하위로는 props라는 특별한 속성을 전달합니다.
그리고 하위에서 상위로는 이벤트만 전달할 수 있습니다.

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

props 속성

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

사용하기 위해선
하위 컴포넌트 속성에 아래의 문법으로 정의합니다.

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

그런 다음 상위 컴포넌트 템플릿에 아래의 문법을 추가합니다.

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

v-bind 속성의 왼쪽 값으로 하위 컴포넌트에 정의한 props속성을 넣고, 오른쪽 값으로 하위 컴포넌트에 전달할 상위 컴포넌트의 data 속성을 지정합니다.

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/dist/vue.js"></script>
    <script>
        ② Vue.component('child-component', {
           ③ props: ['propsdata'],
           ⑤ template: '<p>{{ propsdata }}</p>',
        });new Vue({
            el: '#app',
            data: {
                message: 'Hello Vue!'
            }
        });
    </script>
</body>
</html>

① new Vue()로 인스턴스를 하나 생성합니다.
② Vue.component()를 이용하여 하위 컴포넌트인 child-component를 등록합니다.
③ child-component의 내용에 props 속성으로 propsdata를 정의합니다.
④ HTML에 컴포넌트 태그를 추가합니다. < child-component > 태그의 V-bind 속성을 보면, v-bind:propsdata="message"는 상위 컴포넌트의 message 속성 값인 'Hello Vue!' 텍스트를 하위 컴포넌트의 propsdata로 전달하였습니다.
⑤ child-component의 template 속성에 정의 된 '< p >{{ propsdata }}< /p >는 Hello Vue! 가 됩니다.

위의 내용을 정리하면
뷰 인스턴스의 data 속성에 정의 된 message 속성을 하위 컴포넌트에 props로 전달하여 화면에 나타냅니다.

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

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

이벤트 발생과 수신

그렇다면 하위에서 상위로 보내는 방법은 무엇일까?
그건 이벤트를 발생 시켜(event emit) 상위 컴포넌트에 신호를 보내면됩니다.

이벤트 발생과 수신 형식

이벤트 발생과 수신은 $emit()과 v-on:속성을 사용하여 구현합니다.

// 이벤트 발생
this.$emit('이벤트 명');
// 이벤트 수신
<child-component v-on:이벤트명="상위 컴포넌트의 메서드명"></child-component>

$emit()을 호출하면 괄호 안에 정의된 이벤트가 발생합니다.
그리고 일반적으로 $emit()을 호출 하는 위치는 하위 컴포넌트의 특정 메서드 내부입니다.
따라서 $emit()을 호출할 때 사용하는 this는 하위 컴포넌트를 가리킵니다.

호출한 이벤트는 하위 컴포넌트를 등록하는 태그(상위 컴포넌트의 template 속성에 위치)에서 v-on:으로 받습니다. 하위 컴포넌트에서 발생한 이벤트명을 v-on: 속성에 지정하고, 속성의 값에 이벤트가 발생했을 때 호출될 상위 컴포넌트의 메서드를 지정합니다.

예제

<!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-on:show-log="printText"></child-component>
    </div>

    <script src="https://cdn.jsdelivr.net/npm/vue/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'
            },
            methods: {printText: function() {
                    console.log("received an event");
                }
            }
        });
    </script>
</body>
</html>

이 코드는 child-componentd의 [ show ]버튼을 클릭하여 이벤트를 발생시키고, 발생한 이벤트로 상위 컴포넌트 (여기서 루트 컴포넌트)의 printText()메서드를 실행시키는 예제이다. 과정은 이렇다.

① [show]버튼을 클릭하면 클릭 이벤트 v-on:click="showLog"에 따라 showLog() 메서드가 실행됩니다.
② showLog() 메서드 안에 this.$emit('show-log')가 실행되면서 show-log 이벤트가 발생합니다.
③ show-log 이벤트는 < child-componentd >에 정의한 v-on:show-log에 전달되고, v-on:show-log의 대상 메서드인 최상위 컴포넌트의 메서드 printText()가 실행됩니다.
④ printText()는 received an event라는 로그를 출력하는 메서드 이므로 마지막으로 콘솔에 로그가 출력됩니다.

이와 같은 방식으로 하위 컴포넌트에서 상위 컴포넌트로 신호를 올려보내면 상위 컴포넌트의 메서드를 실행할 수 있습니다.

같은 레벨은 다음에 정리하도록하겠다.

profile
디자이너, 기획자 출신의 개발자

0개의 댓글