Vue의 v-model은 Sugar Syntax일 뿐이다.
문제상황
input element를 처리하는 Component를 만들 때 input value를 parent로 보내려고 한다.
event처리 하거나 callback function을 보낼 것이다.
Vue가 React와 차별 되는 two way binding을 못쓰는 것이 불편할 것이다.
prop으로 전해지는 값은 변경하지 않기를 권장한다. 변경하더라도 v-model로 넘겨주는 값이 primitive 타입이라면
변경해도 추적하지 못한다.
Component를 만들고 v-model로 값을 받아서 input에 two way binding하는 방법은 없을까?
v-model 구현
v-model은 내부적으로 복잡하게 구현 된 것이 아니고
props로 value를 받아서 input 이벤트로 돌려주는 것을 축약한 것이다.
그러면 value를 넘기고 input 이벤트를 만들면 바로 구현이 될까?
props로 받은 value를 input에 v-model로 매칭 시키면 다음과 같은 경고 메세지가 나온다.
` [Vue warn]: Avoid mutating a prop directly since the value will be overwritten whenever the parent component re-renders. Instead, use a data or computed property based on the prop’s value. Prop being mutated: “value” `
여기서 두가지 해결책으로 나눠진다.
- solve1) v-model에 prop대신 computed를 바인딩
Vue Computed는 definedProperty의 get을 사용한다. 자연스럽게 set을 만들어주면 v-model의 input event를 받을 수 있다.
<template>
<input v-model="inputValue"
/>
</template>
<script>
import Vue from 'vue'
export default {
name: 'SelectInput',
props: {
value: {},
},
computed: {
inputValue: {
get: function() {
return this.value
},
set: function(value) {
this.$emit('input', value)
},
},
},
}
- solve2) v-model대신 v-bind:value로 바인딩
<template>
<input
:value="value"
@input="handleInput"
/>
</template>
<script>
export default {
name: 'SelectionPerPage',
props: {
value: {},
},
data() {
const vm = this
return {
handleInput({ target }) {
vm.$emit('input', target.value)
}
}
}
}
</script>
취향에 맞게 쓰면 되지만 solve2는 inheritAttrs: false 를 사용하기 위해 눈에 익혀둘 필요가 있다.