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

컴포넌트는 자체적으로 고유한 유효 범위(scope)를 갖기 때문에 다른 컴포넌트의 값을 직접적으로 참조할 수 없다.

 

컴포넌트의 유효 범위 확인 예제)

<!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>Vue Component Scope</title>
</head>
<body>
    <div id="app">
        <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>
        // 첫 번째 컴포넌트
        let cmp1 = {
            template : '<div>첫 번째 지역 컴포넌트 : {{ cmp1Data }}</div>',
            data: function() {
                return {
                    cmp1Data : 100
                }
            }
        };
        // 두 번째 컴포넌트
        let 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>

결과)

my-component2에서 my-component1의 값을 직접 참조할 수 없기 때문에 출력이 되지 않았다.

 

- 상.하위 컴포넌트 관계

컴포넌트는 직접 다른 컴포넌트의 값을 참조할 수 없다.

따라서 뷰 프레임워크 자체에서 정의한 컴포넌트 데이터 전달 방법을 이용해야 한다.

가장 기본적인 데이터 전달 방법은 상위(부모) 컴포넌트 - 하위(자식) 컴포넌트 간의 데이터를 전달 방법이 있다.

 

지역 또는 전역 컴포넌트를 등록하면 컴포넌트는 자연스럽게 하위 컴포넌트가 된다. 그리고 하위 컴포넌트를 등록한 인스턴스는 상위 컴포넌트가 된다.

 

상위에서 하위로는 props라는 특별한 속성을 전달한다.

그리고 하위에서 상위로는 기본적으로 이벤트만 전달할 수 있다.

 

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

props 속성을 사용하여 데이터를 전달할 수 있다.

먼저 하위 컴포넌트에 props 속성을 정의해야 한다.

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

그 다음 컴포넌트 태그에 v-bind 속성을 추가한다.

<child-component v-bind:속성이름="상위 컴포넌트의 data 속성"></child-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>Vue Props Sample</title>
</head>
<body>
    <div id="app">
        <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) props 속성으로 propsdata를 정의

4) 상위 컴포넌트의 message를 하위 컴포넌트의 propsdata로 전달

5) template 속성에 정의된 {{ propsdata }} 를 message로 전환

 

★ 컴포넌트를 등록함과 동시에 뷰 인스턴스 자체가 상위 컴포넌트가 되어, 부모-자식 컴포넌트 관계가 성립된다.

따라서 props로 데이터 전달이 가능하다.

 

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

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

 

- 이벤트 발생과 수신 형식

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

 

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

하위 컴포넌트에서 발생한 이벤트명을 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>Vue Event Emit Sample</title>
</head>
<body>
    <div id="app">
        <child-component v-on:show-log="printText"></child-component>
        {{ message }}
    </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');
                }
            }
        });

        new Vue({
            el: '#app',
            data: {
                message: 'Hello Vue! passed from Parent Component'
            },
            methods: {
                printText: function() {
                    console.log("received an event");
//                  this.message = 'Hello';
                }
            }
        });
    </script>
</body>
</html>

1) show 버튼을 클릭하면 하위 컴포넌트의 methods 속성에 정의된 showLog() 메서드가 실행된다.

2) $emit에 의해 'show-log' 이벤트가 발생한다.

3) show-log 이벤트는 v-on:show-log에 전달되고, v-on:show-log의 대상인 상위 컴포넌트의 printText() 메서드가 실행된다.

4) printText() 메서드에 의해 콘솔에 로그가 출력된다.

 

 

같은 레벨 또는 관계 없는 컴포넌트 간 통신 - 이벤트 버스

앞에서 배운 컴포넌트 통신은 항상 상위-하위 구조를 유지해야만 데이터를 주고받을 수 있었지만,

이벤트 버스를 이용하면 관계에 상관없이 데이터를 한 컴포넌트에서 다른 컴포넌트로 전달할 수 있다.

 

이벤트 버스를 구현하려면 새로운 인스턴스를 1개 더 생성하고, 새 인스턴스를 이용하여 이벤트를 보내고 받는다.

보내는 컴포넌트에서는 .$emit()을, 받는 컴포넌트에서는 .$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>Vue Event Bus Sample</title>
</head>
<body>
    <div id="app">
        <child-component></child-component>
    </div>
    <script src="https://cdn.jsdelivr.net/npm/vue@2.5.2/dist/vue.js"></script>
    <script>
        let eventBus = new Vue();

        Vue.component('child-component', {
            template: '<div>하위 컴포넌트 영역입니다.<button v-on:click="showLog">show</button></div>',
            methods: {
                showLog: function() {
                    eventBus.$emit('triggerEventBus', 100);
                }
            }
        });

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

1) eventBus라는 변수에 새로운 Vue 인스턴스를 생성

2) 하위 컴포넌트에 methods 속성을 정의하고 클릭시 showLog() 메서드가 실행되도록 한다.

eventBus.$emit으로 이벤트를 발생시키고 100이란 숫자를 전달한다.

3) 상위 컴포넌트의 created 라이프 사이클 훅에 eventBus.$on() 으로 이벤트를 받는 로직을 선언하고

이벤트를 수신할 때 함께 전달받은 인자 값 100을 콘솔 로그에 출력한다.

 

 

이벤트버스를 활용하면 props 속성을 이용하지 않고도 원하는 컴포넌트 간에 직접적으로 데이터를 전달할 수 있지만

컴포넌트가 많아지면 어디서 어디로 데이터를 보냈는지 관리가 되지 않는 문제가 발생한다.

이 문제를 해결하려면 뷰엑스(Vuex)라는 상태 관리 도구가 필요하다.


출처 : Do it! Vue.js 입문

'Vue.js' 카테고리의 다른 글

vee-validate  (0) 2023.01.19
Vuex와 Helper 함수, 모듈화  (1) 2023.01.13
03 인스턴스 & 컴포넌트 - 뷰 컴포넌트  (0) 2022.11.11
03 인스턴스 & 컴포넌트 - 뷰 인스턴스  (0) 2022.11.11
Data Binding  (0) 2022.11.03

+ Recent posts