[ Vue.js ] 인스턴스, 컴포넌트 그리고 통신

식빵·2023년 2월 4일
0

Vue.js

목록 보기
2/4
post-thumbnail

이 글은 Vue 2 버전을 사용합니다. Vue 3 버전과 다른 부분이 있을 수 있습니다.


🍀 Vue 의 시작점, 인스턴스

Vue Application 개발의 가장 첫 시작점은 Vue Instance 를 생성하는 것이다.

let app = new Vue({...});

이 생성자를 통해서 받아내는 객체가 바로 Vue Instance 인데,
이 인스턴스는 다음 목차에 배울 Vue Component 를 담을 수 있는 그릇이로써 사용된다.
이런 이유로 Vue InstanceRoot Component 라고도 표현한다.

일단 여기서 봐둘 것은 생성자의 인자로 넘어간 options object 정도이다.
option object 에는 아래와 같은 속성을 갖을 수 있다.

  • el
  • data
  • template
  • methods
  • created
  • watch

각 속성들에 대한 설명은 지금하지 않겠다.
계속 코딩하면서 자연스럽게 알게되므로, 지금은 "이런 게 있구나~" 하고 넘어가자.





🍀 컴포넌트

1. 컴포넌트란?

오늘 날의 프론트 웹 개발에 사용되는 React, Vue 등의 라이브러리( 또는 프레임워크 )들은
기본적으로 화면을 나누고, 각 나눈 구역 안에서 또 구역을 나누어 각각을 코드로 관리한다.

그리고 이렇게 각각의 구역(또는 화면 요소)를 코드로 만든 것을 컴포넌트 라고 부른다.
컴포넌트의 핵심은 "재사용성" 이다. 중요한 점이니 잊지 말길 바란다.

이미지 출처: https://v2.vuejs.org/v2/guide/components.html#Organizing-Components


2. 컴포넌트 생성법

그렇다면 Vue 에서는 컴포넌트를 어떻게 생성할까?
기본적은 생성법은 아래와 같다.

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Component</title>
  <script src="https://cdn.jsdelivr.net/npm/vue@2.7.14/dist/vue.js"></script>
</head>
<body>
  <div id="app">
    <app-section></app-section>
  </div>
  <script>
    
    // ******* 전역 컴포넌트 생성 *******
    Vue.component(
    	'app-section', // 컴포넌트 태그명
    	{ template: '<h1>Section</h1>'} // 컴포넌트의 내용
    );
    
    new Vue({
      el: '#app',
      components: {
         // ******* 지역 컴포넌트 생성 *******
        'app-footer': {
          template: '<footer>FOOTER</footer>'
        }
      }
    });
  </script>
</body>
</html>


3. 전역 & 지역 컴포넌트

전역 컴포넌트지역 컴포넌트라는 개념이 있다.

일단 위 html 을 봐서 알겠지만 서로 생성 방식이 다르다.
전역은 Vue.component 를 사용하고, 지역 컴포넌트는 Vue instance 의 Options Object
의 components 라는 속성에 넣는 객체의 key-value 를 넣음으로서 생성한다.

하지만 단순히 생성 방식에만 차이가 있는 게 아니다.
전역 컴포넌트와 지역 컴포넌트에는 사실 각각의 제약사항이 있다.

  <div id="app">
    <app-header></app-header>
    <app-footer></app-footer>
  </div>


  <div id="app2">
    <app-header></app-header> <!-- 전역 컴포넌트는 모든 인스턴스에서 접근 가능 -->
    <app-footer></app-footer> <!-- 로컬 컴포넌트는 무조건 components  명시해야 한다 -->
  </div>
  
  <script>
    
    // global component
    Vue.component('app-header', {
      template: '<h1>Header</h1>'
    });

    new Vue({
      el: '#app',
      components: {
        "app-footer": {
          template: '<footer>FOOTER</footer>'
        }
      }
    });

    new Vue({
      el: '#app2'
      // 로컬 컴포넌트를 생성하지 않았다! 에러가 발생할 것이다.
    });
  </script>

에러 발생내역 :


이러한 제약 사항과 관련해서는 공식 문서에서도 볼 수 있는 내용이니,
사용에 있어서 주의하도록 하자.


그런데 우리가 개발할 때는 어떤 걸 더 주로 쓸까?
우리는 "지역 컴포넌트"를 쓰는 경우가 더 많다.

그렇다면 전역 컴포넌트는 언제 쓸까?
전역 컴포넌트는 다른 라이브러리에서 만들고, 우리가 그 라이브러리를 사용할 때
해당 컴포넌트를 호출하여 사용하게 된다.





🍀 컴포넌트와 통신

1. 컴포넌트 데이터의 유효범위

컴포넌트들은 각각 고유한 데이터 를 갖고 있다.
그리고 이 데이터들의 스코프는 자신들이 속한 컴포넌트이다.
그런데 이 데이터를 상위 혹은 하위 컴포넌트에게 넘기려면 어떻게 해야할까?

다행히도 Vue 에는 이러한 데이터 교환 규칙이 정해져있다!

출처: https://vuejs.org

  • 상위 ==> 하위 데이터 전달: props 를 전달하는 방식으로 데이터를 넘긴다.
  • 하위 ==> 상위 데이터 전달: 이벤트를 발생시키는 방식(event-emit)으로 데이터를 넘긴다.

한번 코드를 보면서 이해해보자.



2. props 를 사용한 통신

<!doctype html>
<html lang="ko">
<head>
  <meta charset="UTF-8">
  <script src="https://cdn.jsdelivr.net/npm/vue@2.7.14/dist/vue.js"></script>
  <title>Props</title>
</head>
<body>
<div id="app">
  <!-- v-bind:{props 배열에 지정한 명칭}="{부모 컴포넌트 데이터 이름}"-->
  <app-header v-bind:props_data="message"></app-header>
</div>
<script>
  
  let appHeader = {
    template: '<h1>header {{props_data}}</h1>',
    props: ['props_data'] // 상위 컴포넌트로 부터 데이터를 받기 위한 props 설정
  };
  
  // 만약 상위 컴포넌트로부터 받은 것을 곧바로 자식 컴포넌트에 나오게 하고 싶다면
  let appHeader = {
    template: '<h1>{{props_data}}</h1>', // 이렇게 해주면 된다! 이건 추후에 배움.
    props: ['props_data']
  };
  
  new Vue({
    el: '#app',
    components: {
      'app-header': appHeader
    },
    data: {
      message: 'hi' // 하위 컴포넌트가 받을 data
    }
  });
</script>
</body>
</html>

Vue 개발자 도구를 통해서 확인해보면 아래와 같다.


👉 상위 컴포넌트


👉 하위 컴포넌트


정상적으로 상위 컴포넌트의 data.message 가 하위 컴포넌트의
props.props_data 에 전달된 것을 확인할 수 있다.



3. props reactivity

여기서 눈여겨볼 사항은 props 또한 reactive 하게 동작한다는 것이다.
다시 말해 상위 컴포넌트가 하위 컴포넌트에게 준 data.message 에 변경이 일어나면,
그 값을 전달받은 props 의 값 또한 변경이 전파되는 것이다!



4. event emit 통신

이번에는 하위 컴포넌트에서 상위 컴포넌트로 데이터를 보내보자.

<!doctype html>
<html lang="ko">
<head>
  <meta charset="UTF-8">
  <script src="https://cdn.jsdelivr.net/npm/vue@2.7.14/dist/vue.js"></script>
  <title>Event-Emit</title>
</head>
<body>
  <div id="app4">
    <!-- v-on:{하위 컴포넌트에서 발생한 이벤트의 "이름"}="상위 컴포넌트 메소드 이름" -->
    <app-header v-on:pass="printText"></app-header>
    {{fromChildText}}
  </div>
  <script>
    
    let appHeader = {
      template: '<button v-on:click="passEvent">click me</button>',
      methods: {
        passEvent: function () {
           this.$emit(
    	 	 'pass', // 이벤트 이름을 인자로 준다.
    		 {childData: 1} // 이벤트와 함께 부모 컴포넌트에 보내고 싶은 데이터
    	   ); 
        }
      }
    }
    
    new Vue({
      el: '#app4',
      components: {
        'app-header': appHeader
      },
      methods: {
        printText: function (passedData) {
    	  console.log(passedData); // {childData: 1} 출력...
          this.fromChild = passedData;
        }
      },
      data: {
         fromChildText: ''
      }
    })
  </script>
</body>
</html>

난해하다.
코드 작성 방식의 순서를 숙지하면서 이해해보자.

  1. Component 객체인 appHeader.template<button v-on:click="passEvent">click me</button> 을 줘서 클릭이 발생했을 때, passEvent 메소드가 실행되도록 한다.
  2. passEvent 라는 메소드를 appHeader.methods 에 하나 추가한다.
  3. 추가한 passEvent 메소드 내에서 상위 컴포넌트와 통신하기 위한 이벤트를 this.$emit 을 통해서 발생시킨다.
  4. 컴포넌트 태그를 <app-header> 에 v-on 속성을 다음과 같이 작성해준다.
    v-on:{자식 컴포넌트가 this.$emit 으로 날린 이벤트 이름}="{부모 컴포넌트의 methods}"
  5. 부모 컴포넌트인 Root Compnent, 즉 Vue Instance 에 methods 에 v-on: 속성의 값에 사용된 함수를 작성한다.

좀 복잡하지만 이렇게 규칙을 만들었으니 그냥 지켜주자.
참고로 이후에 v-model 이라는 것을 배우면 이러한 복잡함이 많이 사라진다.





👏 보충 내용

Vue Instance 와 Vue Component 의 차이

결국은 component 도 Vue Instance 의 한 종류이다.
다만 우리가 Root 로서 사용하는 Vue Instance 와 Component 은 서로 애플리케이션
안에서 맡는 역할이 다르다. 그래서 서로 사용법과 생성 시 사용되는 option 들이
조금씩 차이가 난다.

stackoverflow 에서는 아래와 같은 글을 찾았는데, 이것도 차이점을 이해하기에
좋은 문구인거 같아서 추가 했다.

What are the differences?

- Since components are reusable Vue instances, 
  they accept the same options as new Vue, such as data, computed, 
  watch, methods, and lifecycle hooks.  
  The only exceptions are a few root-specific options like el.

- A root Vue instance is a Vue application launcher, 
  Vue component is an extension of the Vue instance.

참고링크:





✨ 참고 링크

profile
백엔드를 계속 배우고 있는 개발자입니다 😊

0개의 댓글