개발/Front-End

Vue 3 Props 사용법 정리 - feat. setup

날고싶은병아리 2022. 7. 1. 07:24

Vue 3 출시 후 꽤 많은 시간이 흘러 stable 해졌다고 판단하여

일부 프로젝트에서 Vue 3 를 사용하기 위한 사전 준비를 하고 있다.

아니다, stable 은 개뿔. 개판이다.

 

Vue 3 에서도 Vue 2 부터 쓰던 문법을 계속 쓸 수 있으므로 전환에는 크게 문제가 없는데

이왕 쓸 거라면 Vue 3 에서 권장하는 방식으로 해야 하지 않겠는가.

 

2022.06.22 - [개발/Front-End] - Vue CLI 를 통한 Vue 프로젝트 생성

 

Vue CLI 를 통한 Vue 프로젝트 생성

상당히 오랫동안 Webpack 을 통해 만들어진 프로젝트를 깎고 깎아 사용하다가 신규 프로젝트를 생성할 일이 생겨 Vue CLI 를 통해 만들어보기로 한다. 일단 Vue CLI 를 실치해야 한다. NPM 과 Yarn 을 프

naveen.tistory.com

Vue 3 도 처음, TypeScritp 도 처음이라 코드가 낮설어 인터넷으로 정보를 계속 찾으며 코드를 짜고 있다.

근데 Vue 버전이 올라가면서 계속 방식이 바뀌고 있어 공식 문서도 구글링 정보도 작동하지 않는 경우가 많다.

 

그중에 가장 당황했던 props 전달 방식을 정리해 보려고 한다.

 


사용 중인 패키지 정보

 

패키지 버전
vue 3.2.37
vue-class-component 8.0.0-0
vue-property-decorator 9.1.2
typescript 4.7.4

 

1. 기본 방식

<script lang="ts">
import { PropType } from "vue";

export default {
  props: {
    printName: {
      type: String,
      required: true,
    },
    printData: {
      type: Object as PropType<{
        printData1?: string;
        printData2?: string;
      }>,
      default: () => ({}),
    },
  },
};
</script>

TypeScript 를 사용하지만 props 내부에 타입 지정이 있기 때문에 별도로 추가가 필요하진 않다.

type: Object as PropType<> 처럼 명시적으로 지정을 해도 된다.

<script lang="ts">
import { defineComponent } from "vue";

export default defineComponent({
  props: {
    printName: {
      type: String,
      required: true,
    },
  },
  setup(props) {
    console.log(props.printName);
  },
});
</script>

Composition API 를 이용해 defineComponent 를 사용해도 동일하다.

 

2. vue-class-component

<script lang="ts">
import { Options, Vue, prop } from "vue-class-component";

class Props {
  printName = prop({
    type: String,
    required: true,
  });
}

@Options({})
export default class LayoutPrint extends Vue.with(Props) {}
</script>

Vue 에 Class 방식을 도입한 방식.

vue-class-component 패키지를 사용하고 prop 라는 함수를 받아 props 를 지정한다.

props 설정 방식은 기존과 동일하다.

 

3. vue-property-decorator

<script lang="ts">
import { Vue } from "vue-class-component";
import { Prop } from "vue-property-decorator";

export default class LayoutPrint extends Vue {
  @Prop({
    type: String,
    required: true,
  })
  printName!: string;
}
</script>

vue-property-decorator 라는 외부 패키지를 이용한다.

Vue Core 팀에게 완벽하게 승인되었다고 하는데,

시스템 코어에 밀접하게 연관이 있는 외부 패키지의 경우

버전 업데이트가 중단되거나 지원이 부실한 경우가 왕왕 생기기 때문에

지속적인 버전 업데이트를 계획중이라면 사용을 한 번 더 고려해야 한다.

사실 공식 패키지도 지원 상태가 댕댕이판이다.

 

4. defineProps

<script setup lang="ts">
const props = defineProps({
  printName: {
    type: String,
    required: true,
  },
});
</script>

script 태그에 setup 속성에 추가하면 코드를 짧고 간결하게 표현할 수 있다.

defineProps 는 따로 import 하지 않아도 사용이 가능하며 Proxy 로 만들어진 Object 값을 반환한다.

<script setup lang="ts">
const props = withDefaults(
  defineProps<{
    printName: string;
  }>(),
  {
    printName: "Vue 3",
  }
);
</script>

TypeScript interface 를 통해 설정도 가능하다.

interface 를 사용할 경우 defautl 값은 withDefaults 라는 내부 함수를 이용해 따로 지정해야 한다.

 


 

프로젝트 생성이 잘못된 건지 Vue 3 가 이상한 건지,

모든 방식에서 required, validator 가 작동하지 않는다.

validator 의 경우 실행은 되는데 false 를 반환해도 에러가 안 난다.

<script setup lang="ts">
const props = defineProps({
  printName: {
    type: String,
    required: true,
    validator: (value) => {
      console.log(value); // 출력
      return false;
    },
  },
});
</script>

console 에서 value 는 찍히는데 에러가 안 난다.

// Parent
<template lang="pug">
.wrap
  PrintLayout // VS Code 에서 에러 표시
</template>

// Children
<script setup lang="ts">
const props = withDefaults(
  defineProps<{
    printName: string;
  }>(),
  {
    printName: "Vue 3",
  }
);
</script>

다행히 defineProps 에 interface 를 사용한 방식은 props 를 넘기지 않으면 VS Code 에서라도 에러를 표시해준다.

더불어 이 방식이 가장 Vue 3 + TypeScript 에서 표준적인 방식인 것 같아 이렇게 코드를 작성하기로 했다.

 

Vue 3 에서 TypeScript 를 정식 지원하는 건 좋은데,

코드를 작성하는 방식은 하나로 통일시켜 주면 좋겠다.