본문 바로가기
카테고리 없음

v-model의 특징 및 문제점, 그리고 활용 방식

by klm hyeon woo 2024. 2. 29.

목차

· v-model 속성

· v-model은 어떤 방식으로 동작할까?

· 무조건 v-model을 사용해도 되는걸까?

· v-model 문법을 사용하여 IME 입력을 처리하는 방법은?

· [부록] Emit과 Listen

· [부록] 컴포넌트에서 emit


v-model 속성

공식 문서에 안내된 v-model 속성의 사용법은 다음과 같다.

<input v-model="inputText"/>

이렇게 사용자의 입력을 받는 UI 요소들에 v-model 이라는 속성을 사용하면 입력 값이 자동으로 뷰 데이터 속성에 연결이 되어진다.

v-model은 어떤 방식으로 동작할까?

v-model 속성은 v-bind와 v-on의 기능 조합으로 동작한다. 매번 사용자가 일일히 v-bind와 v-on 속성을 지정해주지 않아도 좀 더 편하게 개발을 할 수 있게 고안된 문법이며, 앞에서 살펴본 코드를 아래와 같이 변경해도 동작한다.

<input v-bind:value="inputText" v-on:input="updateInput">

 

<script>
    setup(){
        const inputText = ref('');
        const updateInput = (event) => {
            const updatedText = event.target.value;
            const inputText.value = updatedText;
        };
    }
</script>

위의 코드를 이해하기 위해서는 다음 내용을 필수로 인지하고 있어야 한다.

1. v-bind 속성은 뷰 인스턴스의 데이터 속성을 해당 HTML 요소에 연결할 때 사용한다.

2. v-on 속성은 해당 HTML 요소의 이벤트를 뷰 인스턴스의 로직과 연결할 때 사용한다.

3. 사용자의 이벤트에 의해 실행된 뷰 메서드(methods) 함수의 첫 번째 인자에는 해당 이벤트(event)가 들어온다.

 

HTML 입력 요소의 종류에 따라 `v-model` 속성은 다음과 같이 구성이 되어진다.

1. input 태그에는 `value / input`

2. checkbox 태그에는 `checked / change`

3. select 태그에는 `value / change`

무조건 v-model을 사용해도 되는걸까?

입력 싱크가 맞지않는 것을 확인할 수 있다.

빠르게 기능을 구현하고, 프로덕트의 프로토타이핑을 해나갈 떄는 v-model을 사용해도 상관은 없다. 하지만, 현재 시점에서는 IME 입력(한국어, 일본어, 중국어)에 대하여 아래와 같은 문제점이 발생한다. 위 화면을 확인해보면, 한글 입력의 경우 한 글자에 대한 입력이 끝나야지만 데이터가 인풋 박스의 텍스트 값과 동기화가 된다. 위와 같은 v-model의 한계점 때문에 뷰 공식 문서에서는 한국어 입력을 다룰 때 value와 input의 디렉티브를 통한 직접 연결로 사용하는 것을 권고하고 있다.

v-model 문법을 사용하여 IME 입력을 처리하는 방법은?

이렇게 매번 한국어 입력을 처리할 때 v-model의 대체로 직접 이벤트와 값을 조합하여 바인딩 하는 것 자체가 귀찮게 느껴질 수 있다. 하지만 이럴 경우 인풋 컴포넌트를 별도의 컴포넌트로 분리하면 v-model로 편하게 처리를 할 수 있다.

<!-- Main.vue SFC 구조 -->
<template>
    <BaseInput v-model:value="inputText"/>
    <div> {{inputText}} </div>
</template>
 
<script>
    import { ref } from 'vue';
    import BaseInput from '../v-model/BaseInput.vue';
    const inputText = ref("happy day-!");
</script>

해당 부분은 상위 컴포넌트에서 정의한 데이터 값을 하위 컴포넌트로 내려보내는 부분이다. 평소에 사용하던 props 속성 대신 v-model:value를 사용하였으며, 하위 컴포넌트에 value라는 프롭스 속성으로 내려간다는 사실을 추론할 수 있다.

<!-- BaseInput.vue SFC 구조 -->
<template>
    <div>
        <input v-bind:value="value" v-on:input="updateInput">
    </div>
</template>
 
<script setup>
    defineProps({
        props: {
            value: '',
        };
    });
     
    const emit = defineEmits(['update:value']);
    const updateInput = (event) => {
        emit("update:value", event.target.value)
    };
</script>

위 코드의 동작을 간단하게 설명을 하자면, 다음과 같다.

  • BaseInput 컴포넌트의 상위 컴포넌트에서 props로 받은 value를 인풋 태그에 값으로 연결한다.
  • 인풋 태그에서 값이 입력되면 인풋 태그에서 input 이벤트가 발생하고 updateInput 메서드가 실행된다.
  • updateInput 메서드에서 인풋 태그에 입력된 값을 상위 컴포넌트에 update:value 이벤트로 올려 보낸다.

[부록] Emit과 Listen

이벤트에서 emit이란, 해당 이벤트가 발생했다고 알리는 트리거 같은 것이라고 생각하면 된다. 반대로 listen은 이러한 이벤트가 발생했는지 감지한다.

태그에서 v-on 디렉티브를 사용하면, 해당 태그에서 발생한 이벤트를 감지한다.

<MyComponent @이벤트="콜백함수"/>

보통은 여기서 이벤트가 click, keyup 등 기본적인 것들이었지만, 커스텀 이벤트가 들어갈 수 있다.

<MyComponent @some-event="콜백함수"/>

 

[부록] 컴포넌트에서 emit

이 컴포넌트에서 커스텀 이벤트가 발생하려면 $emit 함수를 사용하면 된다.

export default {
    methods: {
        submit() {
            this.$emit('someEvent')
        }
    }
}

컴포넌트 template 내에서도 동일하게 사용이 가능하다.

<template>
    <button @click="$emit('someEvent')"
</template>

props에서처럼 case 자동 변환을 해준다. 하지만 HTML 속성에서는 케밥 케이스, 자바스크립트에서는 카멜 케이스를 보통 사용하기 때문에 위에서처럼 사용하는 것을 추천한다. 그게 아니라면 케밥 케이스로 통일하여 사용을 하는 방법이 있다.


레퍼런스

 

[Vue 3] v-model 폼 입력 바인딩

input이나 textarea 태그에는 value라는 속성이 있습니다. 이를 v-bind로 바인딩해도 사용자가 입력한 값이 데이터에 들어가지 않습니다. 왜냐하면 단방향 바인딩이기 때문이죠. 사용자가 입력했을 때

blogcreator.blog

 

v-model의 동작 원리와 활용 방법

v-model 동작 원리. 한글(IME) 입력 처리. 실용적인 컴포넌트 설계와 활용

joshua1988.github.io

 

댓글