[Vue]v-model을 활용한 양방향 바인딩

2025. 1. 20. 18:02·vue.js

vue 이미지

 

v-model은 Vue의 가장 강력한 기능 중 하나로, 양방향 데이터 바인딩을 간단하게 구현할 수 있습니다. Vue 3.4에서는 defineModel 매크로를 도입하며 기존 방식보다 훨씬 간결하고 직관적으로 v-model을 사용할 수 있게 되었습니다.

 

1. 기존 방식: props와 emit을 사용한 v-model 구현

Vue 3.4 이전에는 v-model을 컴포넌트에서 구현하기 위해 props와 emit을 직접 사용해야 했습니다. 다음은 부모 컴포넌트에서 값을 전달받아 자식 컴포넌트에서 값을 업데이트하는 방법의 예제입니다.

 

기존 방식 예제

<!-- Child.vue -->
<script setup>
const props = defineProps(['modelValue'])
const emit = defineEmits(['update:modelValue'])
</script>

<template>
  <div>Child Input</div>
  <input :value="props.modelValue" @input="emit('update:modelValue', $event.target.value)" />
</template>

 

부모 컴포넌트에서는 다음과 같이 사용할 수 있습니다.

<!-- Parent.vue -->
<script setup>
import { ref } from 'vue'
import Child from './Child.vue'

const count = ref(0)
</script>

<template>
  <h1>Parent: {{ count }}</h1>
  <Child v-model="count" />
</template>

위 방식은 동작은 잘하지만, 코드가 다소 장황합니다. 특히, 다수의 v-model 바인딩을 사용하거나, 값을 동적으로 처리해야 할 경우 코드가 복잡해질 수 있습니다.

 

결과

기존방식 결과

 


2. 새로운 방식: defineModel을 활용한 간결한 v-model 구현

Vue 3.4부터 도입된 defineModel은 v-model의 구현을 훨씬 간단하게 만듭니다. defineModel은 내부적으로 modelValue와 update:modelValue를 처리해주므로, 복잡한 설정 없이 바로 사용할 수 있습니다.

 

defineModel 기본 사용법

<!-- Child.vue -->
<script setup>
const model = defineModel()
</script>

<template>
  <div>Child - defineModel</div>
  <input v-model="model" />
</template>

 

부모 컴포넌트에서의 사용법은 기존과 동일합니다.

<!-- Parent.vue -->
<script setup>
import { ref } from 'vue'
import Child from './Child.vue'

const count = ref(0)
</script>

<template>
  <h1>Parent: {{ count }}</h1>
  <Child v-model="count" />
</template>

이 방식은 코드가 더 간결할 뿐 아니라, 유지보수성이 크게 향상됩니다.

 

결과

defineModel 결과

 


3. 부모-자식-손자 관계에서 v-model 활용하기

기본적으로 v-model은 부모와 자식 간 데이터 동기화를 지원합니다. 하지만, 더 깊은 계층 구조(예: 자식의 자식 컴포넌트)에서도 v-model을 활용하여 데이터를 동기화할 수 있습니다.

 

3단계 계층 구조 예제

 

손자 컴포넌트 (GrandChild.vue)

<!-- GrandChild.vue -->
<script setup>
const model = defineModel()
</script>

<template>
  <div>GrandChild</div>
  <input v-model="model" />
</template>

 

자식 컴포넌트 (Child.vue)

<!-- Child.vue -->
<script setup>
const model = defineModel()
</script>

<template>
  <div>
    <h2>Child: {{ model }}</h2>
    <GrandChild v-model="model" />
  </div>
</template>

<script>
import GrandChild from './GrandChild.vue'
export default {
  components: { GrandChild },
}
</script>
 
부모 컴포넌트 (Parent.vue)
<!-- Parent.vue -->
<script setup>
import { ref } from 'vue'
import Child from './Child.vue'

const count = ref(0)
</script>

<template>
  <h1>Parent: {{ count }}</h1>
  <Child v-model="count" />
</template>

 

동작 원리

  • 부모는 count를 Child 컴포넌트로 전달하고, Child는 이를 다시 GrandChild에 전달합니다.
  • GrandChild에서 입력값을 변경하면, 이 값이 즉시 Child와 부모의 count로 동기화됩니다.
  • 이러한 방식으로 계층 간 데이터를 효율적으로 동기화할 수 있습니다.

결과

3단계 계층 결과


4. v-model과 수정자 활용하기

v-model은 .trim, .number, .lazy와 같은 수정자를 기본적으로 지원합니다. 사용자 정의 수정자도 defineModel을 통해 구현할 수 있습니다.

 

사용자 정의 수정자 예제

다음은 capitalize 수정자를 활용하여 입력값의 첫 글자를 대문자로 변환하는 예제입니다.

<script setup>
const [model, modifiers] = defineModel({
  set(value) {
    if (modifiers.capitalize) {
      return value.charAt(0).toUpperCase() + value.slice(1);
    }
    return value;
  },
});
</script>

<template>
  <input v-model.capitalize="model" />
</template>

결론

Vue 3.4의 defineModel은 v-model 구현을 간소화하고 코드 가독성을 크게 향상시킵니다. 또한, 깊은 계층 구조에서도 간단하게 데이터를 동기화할 수 있어 실무에서도 유용하게 활용될 수 있습니다. 앞으로 Vue 프로젝트에서 v-model을 사용할 때, 자식에서 defineModel을 통해 model을 받아 사용하면 될거 같습니다. 

'vue.js' 카테고리의 다른 글
  • [Vue]라우터를 활용한 Layout 설정
  • [Vue]이미지 업로드 & 다운로드 구현하기
  • [Vue] Slot 제대로 이해하기
  • [Vue] computed(계산된 속성) vs watch(감시자)
당훈이
당훈이
당훈이 님의 블로그 입니다.
  • 당훈이
    당훈IT
    당훈이
  • 전체
    오늘
    어제
    • 분류 전체보기 (40)
      • spring (7)
      • vue.js (8)
      • docker (1)
      • javascript (1)
      • aws (21)
      • database (1)
        • oracle (1)
      • nuxt (1)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    aws dns
    aws route53
    nuxt dedupe
    elb
    Spring
    AWS
    중복요청
    aws spring
    배포
    스프링 배포
    nuxt cache
    ec2 route53
    aws 스프링
    AWS ELB
    route53
    스프링
    nuxt fetch
    AWS EC2
    ec2 domain
    Vue
    nodejs 배포
    ec2 nodejs
    aws domain
    nuxt vue
    ec2 spring 배포
    스프링부트
    EC2
    vue3
    nuxt usefetch
    spring boot
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.3
당훈이
[Vue]v-model을 활용한 양방향 바인딩
상단으로

티스토리툴바