[Vue] Vue시작(2) -Vue 인스턴스 속성, 컴포넌트 등록

권준혁·2020년 12월 6일
0

vue

목록 보기
2/8
post-thumbnail

Vue객체와 인스턴스 속성에 대해서 더 알아볼 필요가 있다.
React를 공부할 때도 createElement 와 컴포넌트의 예약된 속성에 대해서의 공부가 도움이 많이 됐었다.

참고 블로그

Vue객체 인스턴스 속성

new Vue({
  el:,
  template:,
  data: ,
  methods: ,
  created: ,
  watch: ,
});
  • el: 인스턴스가 그려지는 화면의 시작점
  • template: 화면에 표시할 요소
  • data: 데이터
  • methods: 이벤트 함수들
  • created: 라이프사이클 중 하나
  • watch: data에서 정의한 속성이 변경됐을 때 추가 동작을 정의
  • computed: 데이터를 계산한 결과를 속성으로 사용하기 위해 사용

computed와 methods의 차이점은 캐싱 여부이다. computed속성은 내부적으로 데이터를 캐싱하고있다. methods는 매번 새로 호출해서 계산한다.

data는 반응형으로 동작한다. 데이터가 변경되면 자동으로 UI를 업데이트 시킨다. 하지만 초기에 인스턴스가 생성될 때 존재하는 것들만 반응형 이라는 것에 주의해야한다.
인스턴스 생성 후에 속성을 추가하고 업데이트하면 반응형으로 동작하지 않는다.


컴포넌트 단위로 개발을 해보자

전역등록

Vue.component('my-component-name', { /* ... */ })
를 이용해서 컴포넌트를 전역으로 등록한다.

컴포넌트의 이름은 첫 번째 인자로 들어가는데, 케밥표기법 으로 작성하는 것을 권장한다.
MyComponentName처럼 파스칼표기법으로도 할 수 있지만, DOM에 바로 쓸 때는 케밥-표기법 이름만 가능하기 때문에 굳이 쓸 이유는 없다.

이렇게 전역등록한 컴포넌트는 어떤 루트 Vue인스턴스 에서도 사용할 수 있다.

Vue.component('component-a', { /* ... */ })
Vue.component('component-b', { /* ... */ })
Vue.component('component-c', { /* ... */ })

new Vue({ el: '#app' })
<div id="app">
  <component-a></component-a>
  <component-b></component-b>
  <component-c></component-c>
</div>

지역등록

전역등록은 단점이 있다. 사용하지 않는 컴포넌트도 최종 빌드에 포함되는 것이다. 불필요하게 코드 양이 커진다.

이 경우에 컴포넌트를 일반 자바스크립트 객체로 정의할 수 있다.

const ComponentA = { /* ... */ }
const ComponentB = { /* ... */ }
const ComponentC = { /* ... */ }

사용할 때는 components옵션을 통해 쓸 수 있다.

new Vue({
  el: '#app',
  components: {
    'component-a': ComponentA,
    'component-b': ComponentB
  }
})

components객체의 각 속성에서 키가 엘리먼트의 이름이 되고 value에 컴포넌트 객체를 지정하면 된다.

지역 등록된 컴포넌트는 당연히 하위 컴포넌트에서는 사용이 불가능하다.

ESM이용

모듈시스템을 이용해서 불러온 뒤 하위 컴포넌트로 정의해본다.

componentB.vue
import ComponentA from './ComponentA'
import ComponentC from './ComponentC'

export default {
  components: {
    ComponentA,
    ComponentC
  },
  // ...
}

componentB의 템플릿에서 component-a와 component-c 모두 사용 가능하다.

기본컴포넌트 자동으로 전역등록하기

자주쓰이는 컴포넌트를 전역으로 등록하기 위해 일일이 등록하는게 불편할 수 있기 때문에, 자동 전역등록 기능을 제공한다.

웹팩을 쓴다면 require.context를 써서 자주쓰는 기본 컴포넌트들을 전역 등록 할수 있으며, Vue CLI 3+를 쓴다면 그 안에 내장되어 있다.

main.js
import Vue from 'vue'
import upperFirst from 'lodash/upperFirst'
import camelCase from 'lodash/camelCase'

const requireComponent = require.context(
  // 컴포넌트들이 있는 폴더
  './components',
  // 하위 폴더까지 포함할 지 여부
  false,
  // 기본 컴포넌트를 찾는데 사용할 정규표현식
  /Base[A-Z]\w+\.(vue|js)$/
)

requireComponent.keys().forEach(fileName => {
  // 컴포넌트 설정 가져오기
  const componentConfig = requireComponent(fileName)

  // 컴포넌트의 파스칼표기법 이름 가져오기
  const componentName = upperFirst(
    camelCase(
      // 폴더 위치와 무관하게 파일이름 추출
      fileName
        .split('/')
        .pop()
        .replace(/\.\w+$/, '')
    )
  )

  // 컴포넌트를 전역적으로 등록
  Vue.component(
    componentName,
    // `export default`를 이용한 컴포넌트는 `.default`로 컴포넌트
    // 옵션을 추출하고 그렇지 않은 컴포넌트는 모듈의 루트를 호출
    componentConfig.default || componentConfig
  )
})

뜬금없지만 sequelize 모듈이 모델들을 폴더에서 불러오는 코드와 비슷하다.
주석만 순서대로 읽어보면 이해가 잘된다.

정리하면 require.context라는 webpack의 기능을 이용해서 설정한 폴더(첫 번째 인자)에서 파일들을 정규식(3번째 인자)를 이용해 목록을 생성하고, keys().forEach()를 통해 순회한다.

lodash에서 제공하는 함수를 이용해서 camelCase를 pascalCase로 변경, fileName에서는 폴더 경로를 제외한 파일명만을 추출한다.
그런 뒤 반복문 마지막에서 결국 Vue.component()를 이용해 Vue루트 객체의 전역 컴포넌트로 등록하는 것이다.


DOM템플릿 구문분석 경고

DOM을 템플릿으로 사용할 때, Vue는 템플릿 콘텐츠만 가져올 수 있기 때문에 HTML이 동작하는 방식에 고유한 몇 가지 제한사항이 적용된다.
<ul>, <ol>,<select>,<table>과 같은 태그는 하위에 작성 할 수 있는 element가 제한되어있다. 예를들어 <ul> <ol>에는 하위에 <li>가 와야하며 <table>에는 <th> <td>등이 와야 한다.

React의 경우에는 이러한 렌더링 에러가 발생하지 않기 때문에 더 주의해야겠다.

my-row라고 하는 vue컴포넌트는 tr이라는 태그가 상위태그이지만 에러가 발생한다.

<table>
  <my-row>...</my-row>
</table>

해결방법은 is 특수 속성을 사용하는 것이다.

<table>
  <tr is="my-row"></tr>
</table>

profile
웹 프론트엔드, RN앱 개발자입니다.

0개의 댓글