컴포넌트가 무엇인가?


컴포넌트Vue의 핵심 기능 중 하나이다. 컴포넌트를 어떻게 구성하고 생성하냐에 따라 어플리케이션의 개발속도와 코드 가독성, 그리고 효율성(ex. 재사용성)이 차이가 난다.

Vue에서 컴포넌트는 기본 HTML 엘리먼트를 확장하여 재사용 가능한 코드를 모듈화 혹은 캡슐화한 것을 의미한다. 상위 수준에서 컴포넌트는 Vue의 컴파일러에 의해 동작이 추가된 사용자 지정 엘리먼트이다. 경우에 따라 특별한 is 속성으로 확장 된 원시 HTML 엘리먼트로 나타날 수도 있다.

Vue 컴포넌트는 Vue 인스턴스이기도 하다. 그러므로 모든 옵션 객체를 사용할 수 있다. (루트에만 사용하는 옵션은 제외) 그리고 같은 라이프사이클 훅을 사용할 수 있다.

정리해서, 컴포넌트는 어플리케이션을 만들기 위한 작고 독립적인 블록이며 재사용이 가능하다. 이것들을 잘 조합해서 효율적인 개발을 할 수 있다.

Desktop View


컴포넌트 사용방법


컴포넌트를 등록하는 방법은 전역등록(Global Registration)지역등록(Local Registration)이 있다.
Vue-cli 4버전으로 프로젝트를 생성 후 예제를 진행하였다.
해당 내용을 모른다면 [Vue.js] Vue CLI로 프로젝트 생성하기를 참고하기 바란다.
프로젝트는 Vue 2버전으로 진행했다. 프로젝트를 생성하면 아래와 같은 구조를 갖게된다.

image


전역등록

전역등록이란 전역변수처럼 전역에서 컴포넌트를 사용하기 위한 것이다.
components 디렉토리에 GlobalComponents.vue 파일을 생성한다.


  <template>
    <div> {{ text }}</div>
  </template>

  <script>
  export default {
      name:"GlobalComponents",
      data: () => {
          return {
              text : "전역등록된 컴포넌트 입니다."
          }
      }
  }
  </script>

  <style>

  </style>


이제 main.jsGlobalComponents.vueimport하여 vue에 등록만 해주면 된다.
main.js에서 등록을 하는지는 webpack에 대해 알아야 된다.
간단하게 말하면 webpackjs, html, css를 하나로 모아서 빌드할 수 있게 도와주는 도구이다.
그렇기 때문에 모든 리소스는 main.js에서 한번에 모아서 빌드하게 된다. (여기서 main.jswebpack에서 entry 포인트이다.)

따라서, 모든 컴포넌트들을 main.jsimport시킨 다음 Vue 인스턴스에 한번에 바인딩 시켜 렌더링하는 것이다.

추가로 App.vue는 최상위 컴포넌트라고 보면된다.

import Vue from 'vue'
import App from './App.vue'

Vue.config.productionTip = false

import GlobalComponents from './components/GlobalComponents.vue'; // GlobalComponents.vue를 import

Vue.component(GlobalComponents.name, GlobalComponents) // 전역등록

new Vue({
  render: h => h(App),
}).$mount('#app')

전역 컴포넌트를 등록하는 방법:

  Vue.component('tagName', {
    // 옵션
  })


이제 GlobalComponents.vue를 전역에서 사용이 가능하다. 최상위 컴포넌트인 App.vue에서 사용해보자. 컴포넌트를 등록하면 태그 형식으로 사용할 수 있다.

Vue에서는 컴포넌트 태그명을 파스칼로 작성하는 것을 권장한다. 그리고 태그를 사용할 때는 소문자로 작성하고 파스칼 구분을 -를 넣어 작성하면 된다.
파스칼 : HelloWorld -> 태그 작성 : <hello-world></hello-world>

태그명 그대로 작성해도 상관없다.

<template>
  <div id="app">
    <test></test>
    <global-components></global-components>
    <!--  or <GlobalComponents></GlobalComponents> -->
  </div>
</template>

export default {
  name: 'app'
}
</script>

이제 npm run serve로 서버를 실행시켜 localhost:8080/를 확인해보면
성공적으로 전역등록이 완료된 것을 확인할 수 있다.

image


지역등록

Vue 어플리케이션을 개발할 때는 지역등록보다는 전역등록을 사용하는게 보편적이다. 그 이유는 Webpack같은 빌드 시스템을 사용하면 전역등록된 사용하지 않는 모든 컴포넌트가 build에 포함되기 때문이다.

components 디렉토리에 LocalComponents.vue 파일을 생성한다.

<template>
  <div> </div>
</template>

<script>
export default {
    name:"LocalComponents",
    data: () => {
        return {
            text : "지역등록된 컴포넌트 입니다."
        }
    }
}
</script>

<style>

</style>


전역등록Vue 인스턴스에 직접 추가하여 사용했지만, 지역등록은 사용될 곳에 import하여 사용한다.

<template>
  <div id="app">
    <local-component></local-component>
  </div>
</template>

<script>
  import LocalComponent from './components/local-component'

  export default {
    name: 'app',
    components:{
      LocalComponents
  }
  }
</script>

image


data는 반드시 함수

컴포넌트에서 사용하는 data는 반드시 함수여야 한다.

아래의 그림을보면, data는 반드시 함수여야 한다고 경고합니다. image


이런 규칙이 존재하는지 그 이유에 대해 이해하는 것이 중요하다. LocalComponents.vueApp.vue를 아래와 같이 작성해서 실행시킨다.


<template>
  <button v-on:click="count += 1">{{ count }}</button>
</template>

<script>

var data = {count : 0};

export default {
    name:"LocalComponents",
    data: function () {
    return data
  }
}
</script>

<style>

</style>

<template>
  <div id="app">
    <local-component></local-component>
    <local-component></local-component>
    <local-component></local-component>
  </div>
</template>

<script>
  import LocalComponent from './components/local-component'

  export default {
    name: 'app',
    components:{
      LocalComponents
  }
  }
</script>


3개의 컴포넌트가 모두 같은 data 객체를 공유하기 때문에 하나의 count를 증가시키면 모두 증가하게 된다.

image


아래와 같이 수정하면 새로운 데이터 객체를 반환하여 독립적으로 사용할 수 있다.

data: function () {
  return {
    count: 0
  }
}  

image


컴포넌트 작성 방법

Vue.js에서 말하는 컴포넌트는 부모-자식 관계에서 가장 일반적으로 함께 사용하기 위한 것이라고 되어있다.
말 그대로 tree형식으로 사용할 수 있다는 말이다. 이들은 서로 데이터를 주고 받기 위해 props, events($emit)를 사용한다.

Vue.js에서 부모-자식 관계는 아래와 같다.

  • 부모가 자식에게 데이터를 전달할 때 => props
  • 자식이 부모에게 데이터를 전달할 때 => events($emit)

Desktop View


여기서 LocalComponent.vue은 자식컴포넌트고 App.vue가 부모 컴포넌트이다

<template>
  <div id="app">
    <local-components :message="parent_msg" @child-event="check"></local-components>
    <p></p>
  </div>
</template>

<script>
  import LocalComponent from './components/local-component'

  export default {
    name: 'app',
    components:{
      LocalComponents
    },
    data () {
      return {
        parent_msg: '부모컴포넌트에서 보낸 데이터.',
        chile_msg: ''
      }
    },
    methods: {
      check(text) {
        this.chile_msg = text;
      },
    }
  }
</script>



<template>
  <div>
    {{ message  }} 

    <br><br>

    <input type="buttom" @click="siksik" placeholder="자식컴포넌트 데이트 받기">
</div>
</template>

<script>
  export default {
    name: 'LocalComponents',
    props: ['message'],
    methods : {
    siksik : function () {
      let text = '자식컴포넌트에서 전달한 데이터';
      this.$emit("child-event", text);
    },
  }
  }
</script>


부모 => 자식

  • [App.vue] : 자식 컴포넌트로 보낼 message 데이터 객체를 자식 컴포넌트 속성에 추가한다.
  • [LocalComponent.vue] : 부모 컴포넌트에서 받을 message 데이터 객체를 props에 정의한다.
  • [LocalComponent.vue] : 전달받은 message 객체를 이중 중괄호에 바인딩한다.

자식 => 부모

  • [LocalComponent.vue] : 부모에게 전달할 이벤트 $emit을 작성한다. this.$emit("child-event", text);
  • [LocalComponent.vue] : 버튼 클릭시 child-event라는 메서드 이름으로 text 값을 전달한다.
  • [App.vue] : <local-components :message=”parent_msg” @child-event=”check”></local-components> 에서 자식이 보낸 child-event 이벤트 속성을 추가하고 전달받을 이벤트 check를 명시한다.
  • [App.vue] : check 이벤트는 자식에게 전달받은 데이터를 chile_msg에 바인딩하여 화면에 보여준다.

image

image