Vue Class Component with Decorator
기존에 Vue 2 버전을 쓰는 경우 TypeScript의 도입이 매끄럽지 않지만 TypeScript와 같이 사용하기 위하여 Vue.extend()를 사용하여 객체로 만들어 사용하는 방법과 Class Component 형태로 만들어 쓰는 두 가지 방법 중 하나를 선택하여 사용합니다. 현재 운영 중인 Vue.js기반의 application의 경우는 이 중에서 Class Component로 만들어 사용하고 있으며 Decorator를 좀 더 활용하기 위해 추가로 라이브러리를 이용하여 구성했습니다. 그래서 어떻게 Decorator를 이용하여 Vue Class Component를 어떻게 구성했는지 소개하려고 합니다.
Vue Class Component Example
기본적인 Vue Class Component 형태는 vue-class-component를 이용하여 구성합니다.
// https://class-component.vuejs.org/
<template>
<div>
<button v-on:click="decrement">-</button>
{{ count }}
<button v-on:click="increment">+</button>
</div>
</template>
<script>
import Vue from 'vue'
import Component from 'vue-class-component'
// Define the component in class-style
@Component
export default class Counter extends Vue {
// Data
count = 0
// Methods
increment() {
this.count++
}
decrement() {
this.count--
}
// Computed Properties
get countPlusOne() {
return this.count + 1;
}
// Vue lifecycle hooks
mounted() {
console.log('mounted');
}
destroyed() {
console.log('destroyed');
}
}
</script>
Vue Instance를 Vue Class Component 형태로 나타낸 예제입니다.
하지만 vue-property-decorator 라이브러리를 통해 좀 더 Decorator를 활용하려고 합니다. vue-property-decorator는 Vue에서 Class Component 형태로 개발을 도와주는 Decorator를 지원하는 라이브러리이며 vue-class-component 라이브러리를 완전히 의존하지만 Vue에서 정식으로 제공하는 라이브러리는 아닙니다.
vue-property-decorator example
자주 쓰는 Decorator 위주로 예시를 구성했습니다.
// Component.vue
<template>
<!-- template -->
<div ref="divEl">
<AnotherComponent ref="anotherComponent" />
<TestComponent />
</div>
</template>
<script lang="ts">
import {
Vue,
Component,
Prop,
PropSync,
Watch,
Ref,
} from 'vue-property-decorator';
import TestComponent from '@/components/TestComponent.vue';
import AnotherComponent from '@/components/AnotherComponent.vue'
@Component({
name: 'Component',
components: {
TestComponent,
},
})
export default class extends Vue {
@Prop() readonly num!: number;
@PropSync('text', { type: String }) syncedText!: string;
@Watch('flag', { immediate: true, deep: true })
onFlagChanged(val: boolean, oldVal: boolean) {};
@Ref() readonly divEl!: HTMLDivElement;
@Ref() readonly anotherComponent!: AnotherComponent;
private flag = false;
}
</script>
<style lang="scss" scoped>
// style
</style>
@Component, mixins의 경우 vue-class-component에서 제공하는 Decorator를 그대로 사용하며 그 외 Decorator의 경우 vue-property-decorator에서만 사용 가능한 Decorator입니다.
Vue에서 사용하는 props, watch, ref, emit 등을 Decorator를 이용하여 사용할 수 있고 @PropsSync, @ModelSync 등 기존에 없던 옵션들도 Decorator를 이용하여 사용할 수 있습니다. Decorator의 종류는 vue-property-decorator의 github에서 볼 수 있습니다.
Vuex Class Example
Vue의 Store를 구성할 수 있는 Vuex도 Decorator를 이용하여 Class 형태로 만들 수 있습니다. vuex-module-decorators를 이용하여 구성할 수 있지만 vue-property-decorator와 마찬가지로 Vue에서 정식으로 제공하는 라이브러리는 아닙니다.
vuex-module-decorators example
Vuex를 구성하는 방법은 기존과 동일합니다.
// store/index.ts
import Vue from 'vue';
import Vuex from 'vuex';
import ApptModule, { AppState } from './modules/app';
Vue.use(Vuex);
export interface RootState {
app: AppState;
}
export default new Vuex.Store<RootState>({
modules: {
app: AppModule,
},
});
기본적으로 Vuex를 구성하는 State, Mutation, Action, Getters를 Decorator를 이용하여 Class 형태로 구성합니다.
// store/modules/app.ts
import { VuexModule, Module, Mutation, Action } from 'vuex-module-decorators';
export interface AppState {
data: string;
}
@Module({ namespaced: true })
class App extends VuexModule implements AppState {
public data: string = 'snippet';
@Mutation
private SET_DATA(data: string) {
this.data = data;
}
@Action({ commit: 'SET_DATA', rawError: true })
public setData(data: string) {
}
get appData(): string {
return this.data;
}
}
export default App;
마무리
현재 Vue 3가 나왔지만 아직 Vue 2를 사용하고 있거나 레거시로 남아 있는 경우가 있습니다. Vue 2와 TypeScript를 같이 사용하기 위해 Class Component 형태로 개발을 진행한다면 vue-property-decorator와 vuex-module-decorators를 이용하여 좀 더 수월하게 개발할 수 있겠습니다.
참고 자료
https://class-component.vuejs.org/