본문 바로가기

웹 개발/Vue.js

[Vue.js] 컴포넌트 통신

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


다음은 Vue.js에서 컴포넌트 간 데이터 공유가 어떻게 이루어지는지를 설명하는 예제 코드이다. 이 코드는 두 개의 지역 컴포넌트 my-component1과 my-component2를 등록하고, 두 번째 컴포넌트가 첫 번째 컴포넌트의 데이터를 참조하려고 시도하지만 실패하는 상황을 보여준다.

 

 

컴포넌트 간 데이터 공유 문제


Vue.js는 화면을 여러 컴포넌트로 나누어 구성한다. 각 컴포넌트는 자체적인 스코프를 가지고 있으며, 독립적으로 작동한다. 즉, 한 컴포넌트의 데이터는 다른 컴포넌트에서 직접적으로 접근할 수 없다. 이 독립성은 컴포넌트가 재사용 가능하고 유지보수가 쉬워지게 만들지만, 컴포넌트 간 데이터 공유가 필요한 경우 문제를 일으킬 수 있다.

 

 

<html>
    <head>
        <title>
            Vue Component Registration
        </title>
    </head>
    <body>
        <div id="app">
            <h1>뷰 컴포넌트 통신</h1>
            <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>
            //첫 번째 컴포넌트 내용
            var cmp1 = {
                template: '<div>첫 번째 지역 컴포넌트 : {{ cmp1Data }}</div>',
                data: function() {
                    return {
                        cmp1Data : 100
                    }
                }
            }

            // 두 번째 컴포넌트 이름
            var cmp2 = {
                template: '<div>두 번째 지역 컴포넌트 : {{ cmp1Data }}</div>',
                data: function() {
                    return {
                        cmp1Data : cmp1.data.cmp1Data
                    }
                }
            }

            new Vue({
                el: '#app',
                //지역 컴포넌트 등록
                components: {
                    'my-component1' : cmp1,
                    'my-component2' : cmp2
                }
            })
        
        </script>

    </body>
</html>

 

결과

=>

데이터 참조 오류

위 코드에서 cmp2Data는 cmp1.data.cmp1Data를 참조하려고 하지만 아무 값도 표시되지 않는다. 그 이유는 Vue.js 컴포넌트 간에는 직접적인 참조를 허용하지 않기 때문이다. 각 컴포넌트는 독립적인 데이터 스코프를 가지며, 다른 컴포넌트의 데이터를 접근하려면 Vue.js에서 제공하는 특정한 방법을 사용해야 한다.

이 예제는 Vue의 기본적인 설계 철학을 반영한다. Vue는 각 컴포넌트가 독립적으로 동작하고 데이터와 로직이 컴포넌트 내부에 국한되도록 설계되어 있다. 따라서 데이터를 전달하거나 공유하려면 Vue에서 제공하는 규칙에 따라야 한다.

 

상/하위 컴포넌트 관계


다음은 Vue.js에서 상위 컴포넌트가 하위 컴포넌트에 데이터를 전달하는 방식인 props를 설명하는 코드이다. 이 예제에서는 props 속성을 사용하여 상위 컴포넌트의 데이터를 하위 컴포넌트로 전달하는 방법을 보여준다.

 

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


**props**는 상위 컴포넌트에서 하위 컴포넌트로 데이터를 전달할 때 사용하는 속성이다. 상위 컴포넌트는 데이터를 전달하고, 하위 컴포넌트는 해당 데이터를 받아 화면에 표시하거나 다른 로직에 사용할 수 있다. 이 방식은 데이터의 흐름이 부모에서 자식으로 명확하게 유지되도록 도와준다.

 

 

<div id="app">
    <h1>첫 번째 인스턴스 영역</h1>
    <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'],  // 상위 컴포넌트에서 받을 props 정의
        template: '<p>{{ propsdata }}</p>'  // props로 받은 데이터를 출력
    });

    // Vue 인스턴스 생성
    new Vue({
        el: '#app',
        data: {
            message: 'Hello Vue! passed from Parent Component'  // 상위 컴포넌트에서 정의한 데이터
        }
    });
</script>

=>

 

  • Vue 인스턴스 생성: new Vue()로 상위 컴포넌트 인스턴스를 생성하고, data 속성에서 message라는 데이터를 정의한다.
  • 하위 컴포넌트 등록: Vue.component()로 전역 컴포넌트인 child-component를 등록한다. 이 컴포넌트는 props 속성으로 propsdata를 정의하고 있다. 이 propsdata는 상위 컴포넌트에서 전달받은 데이터를 처리한다.
  • HTML 템플릿에 하위 컴포넌트 추가: HTML 템플릿에 <child-component> 태그를 추가하고, v-bind 속성을 통해 상위 컴포넌트의 message 데이터를 propsdata에 바인딩한다. v-bind:propsdata="message"는 상위 컴포넌트의 message 값을 하위 컴포넌트의 propsdata로 전달하는 역할을 한다.
  • 하위 컴포넌트에서 데이터 출력: 하위 컴포넌트는 상위 컴포넌트로부터 전달받은 propsdata 값을 {{ propsdata }}를 통해 화면에 출력한다.

정리

  • new Vue()로 상위 컴포넌트의 인스턴스를 생성하고, 상위 컴포넌트에서 관리하는 데이터를 정의한다.
  • Vue.component()를 통해 하위 컴포넌트를 등록하고, 해당 컴포넌트에서 props로 데이터를 받는다.
  • 상위 컴포넌트의 데이터를 하위 컴포넌트에 전달할 때는 v-bind를 사용하여 데이터를 바인딩한다.
  • 하위 컴포넌트는 전달받은 데이터를 props 속성으로 받아와 화면에 표시하거나 사용할 수 있다.

이 방식으로 상위 컴포넌트는 데이터를 관리하고, 하위 컴포넌트는 그 데이터를 받아 화면에 렌더링하게 된다. props는 부모-자식 간의 명확한 데이터 흐름을 보장하는 중요한 개념이다.

 

 

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


Vue.js는 컴포넌트 간의 데이터 흐름을 일관되게 유지하기 위해 부모에서 자식으로는 props를 통해 데이터를 전달하고, 자식에서 부모로는 이벤트를 통해 상위 컴포넌트로 신호를 보낼 수 있다. 하위 컴포넌트는 $emit() 메소드를 사용하여 상위 컴포넌트로 이벤트를 전달하고, 상위 컴포넌트는 그 이벤트를 v-on 또는 @를 사용해 수신하여 처리할 수 있다.

 

<div id="app">
    <child-component v-on:show-log="printText"></child-component>
</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');  // 'show-log' 이벤트를 부모 컴포넌트로 전달
            }
        }
    })

    // 상위 컴포넌트 인스턴스
    var app = new Vue({
        el: '#app',
        methods: {
            printText: function() {
                console.log("received an event");  // 이벤트를 받으면 메시지 출력
            }
        }
    })
</script>

 

 

코드 흐름 설명

  1. 하위 컴포넌트에서 이벤트 발생:
    • 하위 컴포넌트 child-component에서 버튼을 클릭하면 showLog 메서드가 호출된다.
    • showLog 메서드는 this.$emit('show-log')를 통해 show-log라는 커스텀 이벤트를 상위 컴포넌트로 전달한다.
  2. 상위 컴포넌트에서 이벤트 처리:
    • 상위 컴포넌트는 <child-component>에 v-on:show-log="printText"를 사용해 하위 컴포넌트에서 발생한 show-log 이벤트를 수신한다.
    • 이벤트가 발생하면 상위 컴포넌트의 printText 메서드가 호출되고, 콘솔에 "received an event"라는 메시지가 출력된다.

정리

  • 하위 컴포넌트는 this.$emit()을 사용하여 상위 컴포넌트로 커스텀 이벤트를 발생시킨다.
  • 상위 컴포넌트는 v-on이나 @를 사용하여 하위 컴포넌트의 이벤트를 수신하고, 그에 맞는 메서드를 호출해 처리한다.
  • 이 방식을 통해 컴포넌트 간에 이벤트 기반의 상호작용을 할 수 있으며, 상위 컴포넌트는 하위 컴포넌트에서 발생한 이벤트에 맞게 특정 동작을 처리할 수 있다.

이 방법은 상위 컴포넌트가 하위 컴포넌트에서 발생한 특정 이벤트를 제어하고자 할 때 유용하다.

 

 

같은 레벨의 컴포넌트 간 통신


Vue.js에서는 컴포넌트가 독립적인 유효 범위를 가지기 때문에 한 컴포넌트가 같은 레벨의 다른 컴포넌트의 데이터를 직접 참조할 수 없다. 상위-하위 관계에서는 props와 emit을 통해 데이터를 주고받을 수 있지만, 같은 레벨 간에는 이 방식이 통하지 않는다. 그래서 보통 상위 컴포넌트를 중개하여 데이터를 전달하는 구조를 사용한다. 하지만 이는 불필요한 상위 컴포넌트를 만들어야 한다는 단점이 있다.

이벤트 버스(Event Bus)란?

이벤트 버스는 이런 문제를 해결하기 위한 방법 중 하나이다. 이벤트 버스는 Vue 인스턴스를 이벤트 관리 도구로 사용하여, 같은 레벨의 컴포넌트 간에도 데이터를 쉽게 주고받을 수 있게 해준다. 이 방법을 사용하면 상-하위 관계가 아니더라도 컴포넌트 간에 데이터를 전달할 수 있다.

 

<div id="app">
    <child-component></child-component>
</div>

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

    // Vue 인스턴스 생성
    var app = new Vue({
        el: '#app',
        created: function() {
            // 이벤트 버스를 통해 이벤트 수신
            eventBus.$on('triggerEventBus', function(value) {
                console.log("이벤트를 전달받음. 전달받은 값:", value);
            });
        }
    });
</script>

 

 

 

코드 흐름 설명

  1. 이벤트 버스 생성: var eventBus = new Vue();를 통해 이벤트 버스를 생성한다. 이 Vue 인스턴스는 다른 컴포넌트 간의 이벤트를 주고받기 위한 매개체로 사용된다.
  2. 하위 컴포넌트에서 이벤트 발생: child-component에서 버튼 클릭 시 showLog 메서드가 호출되며, 이 메서드에서 eventBus.$emit('triggerEventBus', 100)을 사용해 이벤트 버스를 통해 이벤트를 발생시킨다.
  3. Vue 인스턴스에서 이벤트 수신: eventBus.$on('triggerEventBus', ...)를 사용해 해당 이벤트가 발생했을 때 값을 수신하고, 콘솔에 값을 출력한다.

 

결론


Vue.js에서 컴포넌트 간의 데이터 전달 방식은 크게 세 가지로 나눌 수 있다:

  1. 상위에서 하위로: 상위 컴포넌트가 하위 컴포넌트로 데이터를 전달할 때는 props를 사용한다. 이는 Vue.js에서 가장 기본적인 데이터 전달 방식이다.
  2. html
    코드 복사
    <child-component v-bind:propsdata="message"></child-component>
  3. 하위에서 상위로: 하위 컴포넌트가 상위 컴포넌트로 데이터를 전달하려면 $emit() 메서드를 사용하여 커스텀 이벤트를 발생시키고, 상위 컴포넌트는 v-on으로 해당 이벤트를 수신한다.
  4. html
    코드 복사
    <child-component v-on:event-name="handleEvent"></child-component>
  5. 같은 레벨 간 통신: 같은 레벨의 컴포넌트 간에는 직접적으로 데이터를 전달할 수 없기 때문에 이벤트 버스와 같은 방법을 사용해야 한다. 이벤트 버스를 통해 상위-하위 관계가 아니더라도 데이터를 주고받을 수 있다.
  6. javascript
    코드 복사
    eventBus.$emit('eventName', data); eventBus.$on('eventName', callback);

Vue.js의 컴포넌트 간 데이터 흐름은 부모-자식 간 통신이 기본이지만, 같은 레벨의 컴포넌트 간 통신에서는 불필요한 상위 컴포넌트를 만들지 않고도 이벤트 버스를 사용해 해결할 수 있다. 이 방법을 통해 더 유연하게 데이터를 주고받을 수 있으며, 특히 복잡한 애플리케이션에서 유용하게 사용할 수 있다.

각 방식은 상황에 맞게 적절히 선택해 사용해야 하며, 단순한 상위-하위 관계에서는 props와 emit을, 복잡한 구조에서는 이벤트 버스Vuex와 같은 상태 관리 도구를 고려할 수 있다.

'웹 개발 > Vue.js' 카테고리의 다른 글

[Vue.js] 뷰 라우터  (0) 2024.10.13
[Vue.js] 뷰 컴포넌트  (0) 2024.10.12
[Vue.js] 뷰 인스턴스  (0) 2024.10.11
[Vue.js] Hello Vue.js 프로젝트 만들기  (0) 2024.10.10
[Vue.js] Vue.js란?  (0) 2024.10.10