Vue3 #2 [변경된 기능 2 - v-model]

템플릿 디렉티브 v-model의 변경된 사용법을 알아보겠습니다.


Vue3는 현재 총 6편의 시리즈로 구성되어 있습니다.

  1. Vue3 #0 [Vue3를 만나다]
  2. Vue3 #1 [변경된 기능 1 - 전역 API]
  3. Vue3 #2 [변경된 기능 2 - v-model] (현재글)
  4. Vue3 #3 [변경된 기능 3 - v-for와 v-if]
  5. Vue3 #4 [새로운 기능 1 - Composition API]
  6. Vue3 #5 [새로운 기능 2 - Teleport와 Fragments]


들어가며

이번 포스팅에서는 변경된 v-model 사용법에 대해서 포스팅할 예정인데요, 이 내용은 변경된 템플릿 디렉티브에 대한 범위로 정의되어 있습니다. 다만, v-model의 경우 실무에서 매우 자주 사용되고 있으므로 좀 자세하게 다뤄보려고 별도의 포스팅을 마련했습니다. 그럼 읽어볼까요?

v-model

v-model은 실무에서 굉장히 자주 사용하는 템플릿 디렉티브 중 하나일 것입니다. v-model에 변경된 부분이 있다면 아마도 필수로 짚고 넘어가야 오류를 방지할 수 있겠죠. 주요 포인트는 다음과 같이 4가지로 정리되어 있습니다.

  1. prop및 event사용법 변경.
  2. .sync 수식어 제거. model 옵션이 제거되고 v-model 전달 인자로 대체.
  3. 다중 v-model 바인딩.
  4. 사용자 지정 수식어 생성 기능 추가.

prop및 event사용법 변경

2.x 버전에 v-model 디렉티브를 컴포넌트에 사용하는 경우입니다. 간단하죠?

<child-component v-model="inputValue"></child-component>

// 위와 동일
<child-component :value="inputValue" @input="inputValue = $event"><child-component>

prop이나 event 이름을 변경하는 경우 2.x 버전에서는 model 옵션을 이용합니다. 현재 개발 중인 코드를 잠시 빌려 위 경우를 적용해보니 다음과 같이 바꿔볼 수 있었습니다. 대략적인 구조만 확인해주세요.

// parent
<child-component v-model="inputValue"></child-component>

// child
<template>
	<input type="text" v-model="inputNumber" />
</template>

<script>
export defalut {
	model: {
		prop: 'number'
	},
	props: {
		number: {
			type: String,
			default() {
				return '';
			},
		}
	},
	computed: {
		inputNumber: {
			get() {
				return this.number;
			},
			set(value) {
				this.$emit('input', value);
			},
		},
	},
}
</script>

value로 처리되어야 하는 prop을 number라는 이름으로 재정의하게 되면 다른 용도로 value라는 네이밍을 사용할 수 있게 됩니다.

vue3의 경우를 살펴볼까요?

기본적으로 valuemodelValue로, event 전달은 update:modelValue로 변경되었습니다.

// child
<script>
export defalut {
	props: {
		modelValue: {
			type: String,
			default() {
				return '';
			},
		}
	},
	computed: {
		inputNumber: {
			get() {
				return this.modelValue;
			},
			set(value) {
				this.$emit('update:modelValue', value);
			},
		},
	},
}
</script>

나머지는 다음 내용과 연관되므로 함께 살펴보겠습니다.

.sync 수식어 제거. model 옵션이 제거되고 v-model 전달인자로 대체

조금 전 2.x버전에서의 예제는 다음과 같이 바꿔볼 수 있습니다.

// parent
<child-component :number.sync="inputValue"></child-component>

// child
<template>
	<input type="text" v-model="inputNumber" />
</template>

<script>
export defalut {
	model: {
		prop: 'number'
	},
	props: {
		number: {
			type: String,
			default() {
				return '';
			},
		}
	},
	computed: {
		inputNumber: {
			get() {
				return this.number;
			},
			set(value) {
				this.$emit('update:number', value);
			},
		},
	},
}
</script>

부모 컴포넌트와의 데이터 바인딩을 update:propName 형식으로 변경하고 부모 컴포넌트에서는 .sync 수식어를 사용했습니다. 양방향 바인딩의 몇 방법 중 하나인데, 사실 실무에서는 거의 기본 방법으로만 개발해보았기 때문에 이점에 대해서는 정확한 설명을 하기 어렵네요. 글을 참고해보시면 도움이 될 것으로 생각됩니다.

어쨌든 히스토리를 간단히 보자면 2.0 버전에서 제거되었다가 2.3에서 부활한 방법인데 양방향 바인딩의 사용은 매우 유의해야 함을 알 수 있는 대목입니다.

그런데 Vue3에서는 .sync 수식어가 다시 제거되었네요! 이와 함께 model 옵션도 제거되면서 해당 기능을 v-model 전달 인자가 대체하도록 변경되었습니다.

// vue3
<child-component v-model:number="inputValue"></child-component>

다중 바인딩

v-model은 vue2.x버전에서는 v-model은 오직 하나의 바인딩만 가능했습니다. vue3버전부터는 다중으로 바인딩할 수 있습니다.

// parent
<child-component v-model:number="inputValue" v-model:text="inputText"></child-component>

// 위와 동일
<child-component
	:number="inputValue"
	@update:number="inputValue = $event"
	:text="inputText"
	@update:text="inputText = $event"
></child-component>

사용자 수식어 생성 기능 추가

이 내용은 공식 홈페이지의 내용 설명이 매우 잘 되어 있으므로 링크로 대체합니다. (https://v3.ko.vuejs.org/ko-KR/guide/component-custom-events.html##handling-v-model-modifiers)

마치며

이번 포스팅을 준비하면서 그동안 실무에서 상당히 제한적인 기능만 사용했구나… 하는 생각이 들었습니다. 제공되는 모든 기능을 적절한 곳에 활용하며 작업할 수 있도록 코드 이해도를 올려야겠습니다. 그럼 다음 포스팅에서 뵙겠습니다. 이 글이 도움이 되셨다면 구독과 좋아요, 알림ㅅ..

참고자료