Engineering note ยท Vue

defineModel ๊ณผ defineProps ์˜ ์ฐจ์ด

2024๋…„ 06์›” 04์ผ์ดํ˜„์ˆ˜
ํƒœ๊ทธvue3composition-apireactivitydefinemodel

Vue 3.4 defineModel ๋งคํฌ๋กœ์™€ ๊ธฐ์กด props/emit ๊ธฐ๋ฐ˜ v-model ๊ตฌํ˜„์˜ ๋‚ด๋ถ€ ์ƒํƒœ ์ฒ˜๋ฆฌ ์ฐจ์ด๋ฅผ ๋น„๊ตํ•˜๊ณ , ๋ถ€๋ชจ ๋ฏธ๋ฐ”์ธ๋”ฉ ์‹œ local ref ํ• ๋‹น์œผ๋กœ ์กฐ๊ฑด๋ฌธ ๋ถ„๊ธฐ์—์„œ ๋ฐœ์ƒํ•˜๋Š” ์˜ค๋™์ž‘ ์›์ธ๊ณผ ํ•ด๊ฒฐ ๋ฐฉ๋ฒ•์„ ์ •๋ฆฌํ•œ๋‹ค.

Vue 3.4 ์ด์ƒ์—์„œ ๋„์ž…๋œ defineModel()์„ ์‚ฌ์šฉํ•˜๋„๋ก ๋ฆฌํŒฉํ„ฐ๋งํ•˜๋‹ค๊ฐ€ ์กฐ๊ฑด๋ฌธ ๋ถ„๊ธฐ์—์„œ ์˜ˆ์ƒ ๋ชปํ•œ ์˜ค๋™์ž‘์ด ์ผ์–ด๋‚ฌ๋‹ค. ๋ถ€๋ชจ ์ปดํฌ๋„ŒํŠธ๊ฐ€ v-model์„ ๋ฐ”์ธ๋”ฉํ•˜์ง€ ์•Š์•˜์„ ๋•Œ ๋‘ ๋ฐฉ์‹์ด ๋‚ด๋ถ€ ์ƒํƒœ๋ฅผ ์ฒ˜๋ฆฌํ•˜๋Š” ๋ฉ”์ปค๋‹ˆ์ฆ˜์ด ๋‹ฌ๋ž๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

๊ธฐ์กด props์™€ emit์˜ ๋‹จ๋ฐฉํ–ฅ ๋™์ž‘

๊ธฐ์กด defineProps์™€ defineEmits ์กฐํ•ฉ์—์„œ๋Š” ๋ถ€๋ชจ๊ฐ€ v-model์„ ๋„˜๊ธฐ์ง€ ์•Š์œผ๋ฉด ์ž์‹์˜ props.modelValue๋Š” undefined๊ฐ€ ๋œ๋‹ค. ์ž์‹ ์ปดํฌ๋„ŒํŠธ ๋‚ด๋ถ€์—์„œ ์™ธ๋ถ€ ๋ฐ”์ธ๋”ฉ ์œ ๋ฌด๋ฅผ ํ™•์ธํ•˜๊ฑฐ๋‚˜ ์„ ํƒ๋œ ํ•ญ๋ชฉ์˜ ํด๋ฐฑ์„ ๊ณ„์‚ฐํ•  ๋•Œ props.modelValue๊ฐ€ undefined์ธ์ง€ ๊ฒ€์‚ฌํ•˜๋Š” ์ฝ”๋“œ๋ฅผ ํ™œ์šฉํ–ˆ์—ˆ๋‹ค.

ts
// ๊ธฐ์กด props + emits ๊ธฐ๋ฐ˜ ๋ถ„๊ธฐ ๋กœ์ง
const props = defineProps<{
  modelValue?: string
  modelObject?: SelectOption
}>()

const emits = defineEmits<{
  (e: 'update:modelValue', value: string): void
  (e: 'update:modelObject', option: SelectOption): void
}>()

const currentValue = computed(() => {
  if (exists(props.modelValue)) {
    return props.modelValue
  } else if (props.modelObject) {
    return props.modelObject.value
  } else {
    return null
  }
})

function selectItem(item: SelectOption) {
  emits('update:modelValue', item.value)
  emits('update:modelObject', item)
}

์ด ๋ฐฉ์‹์—์„œ๋Š” update:modelValue ๋ฅผ ๋ฐœ์ƒ์‹œ์ผœ๋„ props.modelValue์˜ ๊ฐ’ ์ž์ฒด๊ฐ€ undefined์—์„œ ๋ฐ”๋€Œ์ง€ ์•Š๋Š”๋‹ค. ์ฐธ์กฐํ•  ๋ณ€์ˆ˜๊ฐ€ ์—ฐ๊ฒฐ์ด ์•ˆ๋˜์—ˆ๊ธฐ ๋•Œ๋ฌธ.. ๋ถ€๋ชจ๊ฐ€ ๋ณ€๊ฒฝ๋œ ๊ฐ’์„ ๋‹ค์‹œ props๋กœ ๋‚ด๋ ค์ค˜์•ผ ์ž์‹ ๋‚ด๋ถ€ ๊ฐ’์ด ๊ฐฑ์‹ ๋จ.

defineModel ์ „ํ™˜ ํ›„

props์™€ defineModel์˜ ๋ถ€๋ชจ ๋ฏธ๋ฐ”์ธ๋”ฉ ๋™์ž‘ ๋น„๊ต

๋ณด์ผ๋Ÿฌํ”Œ๋ ˆ์ดํŠธ ์ฝ”๋“œ๋ฅผ ์ค„์ด๊ธฐ ์œ„ํ•ด defineModel()์„ ์ ์šฉํ•˜๊ณ  modelValue.value = item.value์ฒ˜๋Ÿผ ์ง์ ‘ ๋ฐ˜์‘ํ˜• ์ƒํƒœ๋ฅผ ์ˆ˜์ •ํ•˜๋„๋ก ์ฝ”๋“œ๋ฅผ ๋ฐ”๊พธ๋ฉด์„œ ๋ฌธ์ œ๊ฐ€ ์ƒ๊ฒผ๋‹ค.

ts
// defineModel() ๊ธฐ๋ฐ˜์œผ๋กœ ๋ฆฌํŒฉํ„ฐ๋งํ•œ ์ฝ”๋“œ
const modelValue = defineModel<string>()
const modelObject = defineModel<SelectOption>('modelObject')

const currentValue = computed(() => {
  if (exists(modelValue.value)) {
    return modelValue.value
  } else if (modelObject.value) {
    return modelObject.value.value
  } else {
    return null
  }
})

function selectItem(item: SelectOption) {
  // defineModel์ด ๋ฐ˜ํ™˜ํ•œ ref์— ์ง์ ‘ ํ• ๋‹น
  modelValue.value = item.value
  modelObject.value = item
}

defineModel ์€ ๋ถ€๋ชจ์™€ ์–‘๋ฐฉํ–ฅ ๋ฐ”์ธ๋”ฉ๋˜๋Š” ref ๊ฐ์ฒด๋ฅผ ์ž์‹ ๋‚ด๋ถ€์—์„œ ์ž๋™์œผ๋กœ ์ƒ์„ฑํ•œ๋‹ค. ๋ถ€๋ชจ๊ฐ€ v-model์„ ์‚ฌ์šฉํ•˜์ง€ ์•Š์•˜๋”๋ผ๋„, ์ž์‹ ์ปดํฌ๋„ŒํŠธ ์•ˆ์—์„œ๋Š” ๋‹จ์ˆœํ•œ local ref ๋กœ ๋™์ž‘ํ•œ๋‹ค. modelValue.value = item.value ๋กœ ๊ฐ’์„ ํ• ๋‹นํ•˜๋ฉด ์ž์‹ ๋‚ด๋ถ€ local ref ์— ๊ฐ’์ด ์„ธํŒ…๋˜๋Š” ๊ฒƒ.

๊ทธ ๊ฒฐ๊ณผ ๋ถ€๋ชจ ์ปดํฌ๋„ŒํŠธ์—์„œ๋Š” selectItem ํ˜ธ์ถœ ์ดํ›„ exists(modelValue.value) ์กฐ๊ฑด๋ฌธ์ด true๋กœ ํ‰๊ฐ€๋˜์–ด modelObject.value ๋ถ„๊ธฐ๋ฅผ ํƒ€์ง€ ๋ชปํ•˜๊ณ  ์˜ค๋™์ž‘์ด ๋‚œ๋‹ค.

๋ถ€๋ชจ๊ฐ€ ์‹ค์ œ๋กœ ํ•ด๋‹น prop์„ ์ „๋‹ฌํ–ˆ๋Š”์ง€ ์—„๊ฒฉํ•˜๊ฒŒ ํŒ๋ณ„ํ•ด์•ผ ํ•œ๋‹ค๋ฉด useAttrs() ๋˜๋Š” defineProps๋ฅผ ํ•จ๊ป˜ ํ™•์ธํ•ด ๋ถ€๋ชจ ์ „๋‹ฌ ์—ฌ๋ถ€๋ฅผ ์ฒดํฌํ•œ๋‹ค.

์ข‹์•„์š”์™€ ๋Œ“๊ธ€

๋Œ“๊ธ€ ๋‚จ๊ธฐ๊ธฐ

๋Œ“๊ธ€ 0๊ฐœ

๋Œ“๊ธ€์„ ๋ถˆ๋Ÿฌ์˜ค๋Š” ์ค‘์ž…๋‹ˆ๋‹ค.