mingg IT

[Vue] Vue3+typescript 공통 컴포넌트 만드는 방법 본문

FrontEnd

[Vue] Vue3+typescript 공통 컴포넌트 만드는 방법

mingg123 2022. 11. 18. 17:42

보통 우리가 부모컴포넌트에서 자식컴포넌트로 데이터를 넘겨주고, 변경하기 위해선 props 와 emit을 주로 사용한다. 

 

공통 컴포넌트를 만들면서 props로 전달받은 값을 직접 변경할 수 없기 때문에 Object로 통째로 넘겨주거나(v-model을 사용하기 위해) 혹은 emit을 이용해서 결국 부모컴포넌트에서 emit을 이용해 받아온 값으로 수정을 해주었다.

쓰면서 너무 불편했고 공통 컴포넌트가 맞나 생각이 들던 와중에 새로운 방법을 발견했다.

 

container.vue (부모컴포넌트임)

<template>
  <List
    v-model:time="dummy.time"
    v-model:duration="dummy.duration"
    />
</template>

<script lang="ts">

import { defineComponent, ref } from 'vue'

interface containerType {
  time : string;
  duration: number;
}

export default defineComponent({
  name: 'container',
  setup() {
    const dummy = ref<containerType>({time: 'DAY', duration:1});
    return {dummy}
  }
})
</script>

 

List라는 공통 컴포넌트를 만들고 여러군데에서 사용한다고 가정하자.

보통 우리가 props를 넘겨줄땐 :time="dummy.time" 을 사용한다.

허나 v-model:time="dummy.time"으로 넘겨준 것을 확인할 수 있다.

 

이렇게 v-model:{props이름} 을 통째로 넘겨주면 vue 내부에서 emit을 만든다고 한다.

 

그러면 공통컴포넌트인 List에선 어떻게 사용해주면 될까?

 

List.vue (공통 컴포넌트)

<template>
    <div class="form-group mr-1 ml-1">
      <label for="timeLabel">시간 단위</label>
      <select :value="time" @change="changeData($event, 'time')" class="custom-select" id="timeLabel" style='width: 100px'>
        <option v-for="(day, index) in repeatTimeList" :key="index">
          {{day}}
        </option>
      </select>
    </div>
    <div class="form-group mr-3">
      <label for="durationLabel">기간</label>
      <input :value="duration" @change="changeData($event, 'duration')" type="number" class="form-control form-control-sm repeat_input_form" id="durationLabel" placeholder="초기화 전체 기간을 입력하세요">
    </div>
</template>

<script lang="ts">

import { defineComponent, PropType, ref, toRefs } from 'vue'
import { Time } from '@/models/store'

export default defineComponent({
  name: 'List',
  props: {
    time: String as PropType<Time>,
    duration: Number as PropType<number>,
  },
  emits: ['update:time', 'update:duration'],
  setup(props, { emit }) {
    const repeatTimeList = ref<Time[]>(['DAY', 'MONTH']);

    function changeData(event: Event, target: string) {
      switch(target) {
        case 'time':
          emit('update:time', (event.target as HTMLSelectElement).value);
          break;
        case 'duration':
          emit('update:duration', (event.target as HTMLSelectElement).value);
          break;
      }
    }
    return { repeatTimeList, setRepeatData }
  }
})
</script>
<style lang="scss" scoped>
.repeat_input_form {
  min-height: 35px;
}

</style>

보면 emits로 ['update:{props이름}]  설정해주고, 전달받은 props들을 :value로 보여준다.

변경같은경우에는 @change 이벤트를 이용하여 emit을 불러와주면 된다. 

 

이러면 부모컴포넌트에서 emit과 관련된 부분을 전혀 신경쓸 필요없이 List(공통컴포넌트)에서 데이터의 변경을 관리할 수 있다. 

 

드디어 진정한 공통 컴포넌트의 의미를 가지게 된것 같다.

기회가되면 저렇게 사용하지 않고 기존 방식대로 부모컴포넌트에서 emit을 썼을 경우를 보여주며 비교 하겠음. 

 

 

혹시 'update:{props이름}' 인데 props를 object로 넘길수도 있는지 아는사람 알려주면 감사하겠다..  props로 object덩어리만 넘기게.. 너무많아서 .. 

(부족한 부분 있으면 댓글 남겨주시면 감사하겠습니다.)

 

Comments