[VUE3 신기능 시리즈#1] 새로운 데이터 바인딩 패턴: defineModel 활용하기
소개
Vue에서는 데이터 흐름 관리를 위한 다양한 방법을 제공하고 있습니다. 그 중에서도 props
와 emit
을 이용한 방식이 널리 사용되어 왔습니다. 그러나 최근에 나온 Vue 3.3에서는 이러한 데이터 관리를 더욱 편리하게 해주는 새로운 기능인 defineModel
이 등장했습니다. 이번 글에서는 이전에 주로 사용해온 props
와 emit
대신 defineModel
을 활용하여 데이터 흐름을 관리하는 경험에 대해 소개하고자 합니다.
기존 데이터 흐름 관리 방식 : props와 emit
Vue에서는 부모 컴포넌트에서 자식 컴포넌트로 데이터를 전달할 때 props
를 사용하고, 그 반대의 경우에는 emit
을 통해 이벤트를 발생시켜 부모 컴포넌트로 데이터를 전달합니다. 이러한 방식은 간단하고 직관적이지만, 데이터 흐름이 복잡해지거나 중첩된 컴포넌트 구조에서는 유지보수가 어려울 수 있습니다.
새로운 데이터 흐름 관리 방식 : defineModel
Vue3에서는 defineModel
을 활용하여 데이터 모델을 더 명확하게 정의하고 관리할 수 있습니다. 이를 통해 데이터의 구조와 유효성 검사를 강화할 수 있으며, 컴포넌트 간의 데이터 흐름을 더욱 효율적으로 관리할 수 있습니다.
defineModel을 사용하기 위한 준비
Vue 3.3에서 실험적인 기능으로 소개된 definemodel
은 Vue 3.4 버전부터 안정적으로 지원되고 있습니다. Vue를 3.4 버전으로 업그레이드할 때, 아래의 종속성도 함께 업데이트해야 합니다.
- Volar / vue-tsc@^1.8.27 (필수)
- @vitejs/plugin-vue@^5.0.0 (Vite를 사용하는 경우)
- nuxt@^3.9.0 (Nuxt를 사용하는 경우)
- vue-loader@^17.4.0 (webpack 또는 vue-cli를 사용하는 경우)
defineModel 사용하기
defineModel 이전의 코드
<!-- InputBasic.vue -->
<script setup>
import { defineProps, defineEmits } from "vue";
const props = defineProps(["value"]);
const emit = defineEmits(["update:value"]);
function onInput(e) {
emit("update:value", e.target.value);
}
</script>
<template>
<div class="input-basic-comp">
<input type="text" placeholder="이름" :value="value" @input="onInput" />
</div>
</template>
컴포넌트의 양방향 바인딩을 지원하기 위해 props
와 emit
을 사용하였습니다. 부모 컴포넌트로부터 데이터를 받아오기 위해 props
를 사용하고, 데이터가 변경되었을 때 부모 컴포넌트에게 알리기 위해 emit
을 사용하는 것을 보여줍니다.
defineModel 적용 후
<!-- InputBasic.vue -->
<script setup>
import { defineModel } from "vue";
const name = defineModel();
</script>
<template>
<div class="input-basic-comp">
<input type="text" placeholder="이름" v-model="name" />
</div>
</template>
defineModel
을 적용한 코드입니다.
부모 컴포넌트에서 v-model
로 선언된 데이터(name
)는 자식 컴포넌트에서 defineModel
로 간편하게 연결할 수 있습니다. 이렇게 함으로써 자식 컴포넌트는 자동으로 해당 데이터를 props
로 선언하고, 변경 사항을 부모 컴포넌트로 emit
하는 ref
를 반환받게 됩니다.
defineModel
을 사용함으로써 명시적으로 데이터 모델을 정의할 수 있으며, 데이터의 변화를 감지하고 이에 반응하는 데 훨씬 효율적입니다. 이를 통해 코드의 가독성과 유지보수성을 향상시킬 수 있습니다.
defineModel
defineModel arguments
// 필수로 설정
const model = defineModel({ required: true })
// 기본값 설정
const model = defineModel({ default: 0 })
// 타입 설정
const model = defineModel({ type: String })
// 로컬 변수로 설정하여 부모로부터 전달되지 않아도 사용할 수 있음.
const model = defineModel({ local: true })
// 첫 번째 매개변수에 이름, 두번째 매개변수에 설정값을 추가
const model = defineModel('model', { required: true })
Multiple bindings
// 여러 개의 모델 정의
const firstName = defineModel('firstName')
const lastName = defineModel('lastName')
프로젝트 적용
<!-- InputEmail.vue -->
<script setup>
import { ref, defineModel } from 'vue';
const email = defineModel('email', {
default: '',
});
const emailChk = defineModel('emailChk', {
default: true,
});
defineProps({
placeholder: {
type: String,
default: '이메일 주소 입력',
},
// ...생략
});
// 이하 생략
</script>
<template>
<div class="input-wrapper">
<input
type="text"
class="input-email"
:class="{ error: !emailChk && validChkBox }"
:placeholder="placeholder"
v-model="email"
/>
</div>
</template>
<!-- Parent.vue -->
<script setup>
import InputEmail from '@/component/InputEmail.vue'
const email = ref(''); // 이메일 값
const emailChk = ref(false); // 이메일 유효성 검사 결과
</script>
<template>
<InputEmail
placeholder="이메일주소"
v-model:email="email"
v-model:emailChk="emailChk"
/>
</template>
핀퐁 웹 페이지에서 이메일 입력창을 구현하기 위해 defineModel
을 활용했습니다.
부모 컴포넌트에서 지속적인 감시가 필요한 이메일 입력값인 email
과 유효성 검사 값을 나타내는 emailChk
에 defineModel
을 사용했습니다. 반면에 일회성으로 자식 컴포넌트에게 전달되는 placeholder
는 이전의 방식대로 props
로 처리하였습니다. 이렇게 함으로써 감시가 필요한 상태와 일회성 데이터 간에 명확한 구분이 이루어져 코드의 가독성이 향상되었습니다.
결론
defineModel
을 활용하는 과정을 통해 데이터 흐름이 보다 명확하게 정의되고 관리되며, 코드가 더 간결해졌습니다.
새로운 기능을 활용하여 더 나은 개발 경험을 얻었으며, 앞으로도 VUE 공식 문서와 업데이트를 주시하여 최신 기능들을 적극적으로 활용할 것입니다.
참고
https://escuelavue.es/en/devtips/vue-3-modelvalue-definemodel-macrohttps://blog.vuejs.org/posts/vue-3-4#potential-actions-neededhttps://vuejs.org/api/sfc-script-setup.html#definemodelhttps://vuejs.org/guide/components/v-model.html
헥토데이터는 데이터 기반 다양한 서비스를 지원하는 기업입니다. 온라인에 분산된 데이터를 실시간으로 제공하기 위해 클라이언트 엔진과 웹 API를 활용합니다. 유수의 비대면 대출 핀테크 서비스가 선택한 헥토데이터의 CODEF API. 꼼꼼한 보안과 빠른 대응으로 기업이 자사 서비스에만 집중할 수 있도록 돕는 CODEF API에 대해 아래 배너를 눌러 확인해 보세요.
본 페이지 내의 모든 콘텐츠는 저작권법에 의해 보호받는 저작물로서, 모든 사용 권리는 ㈜헥토데이터에게 있습니다. 별도의 저작권 표시 없이 무단으로 사용하는 것을 금지하며, 자세한 저작권 정책은 해당 링크를 참고하시기 바랍니다. Copyright 2024.㈜헥토데이터 All rights reserved.