Vue3 데이터 전달
Vue3의 상위 컴포넌트와 하위 컴포넌트 간 여러가지 데이터 전달 방법을 소개 하는 시간입니다.
기초적인 내용과 제가 검색하며 새로 알게 된 유용한 방법이 있어 공유 드리고자 주제를 선정하였습니다.
defineExpose()
vue3에서 defineExpose란 하위 컴포넌트에서 선언된 함수(API)를
상위 컴포넌트에서 직접적으로 호출(import)하여 사용할 수 있는 함수입니다.
하위 컴포넌트
<script setup>
import { ref, defineExpose } from 'vue'
const childNumber = ref(1);
defineExpose({ childNumber })
</script>
상위 컴포넌트
<template>
<ChildComponent ref="$childRef"/>
<button type="button" @click="submit">submit</button>
</template>
<script setup lang="ts">
import {ref} from "vue";
const $childRef = ref();
const submit = () => {
const {childNumber} = $childRef.value;
alert(`exposeChildNumber: ${childNumber}`);
}
</script>
defineProps() & defineEmits()
vue3에서 데이터 전달을 위해 가장 먼저 접하는 props와 emits를 입니다.
하위 컴포넌트
<template>
<h1></h1>
<button type="button" @click="increaseParentNumber">
increaseParentNumber
</button>
</template>
<script setup lang="ts">
import {defineProps, defineEmits} from 'vue';
const props = defineProps<{
parentNumber: number
}>();
const emits = defineEmits<{
(e: 'increaseParentNumber', value: number): void;
}>();
const increaseParentNumber = () => {
emits('increaseParentNumber', 1);
}
</script>
상위 컴포넌트
<template>
<ChildComponet
:parent-number="parentNumber"
@increase-parent-number="increaseParentNumber"
/>
</template>
<script setup lang="ts">
import {ref} from "vue";
const parentNumber = ref(0);
const increaseParentNumber = (value: number) => {
parentNumber.value += value;
}
</script>
defineModel()
제가 새로 알게되었고 소개드리고 싶었던 방법입니다.
상위 컴포넌트에서 v-model을 통해 사용될 수 있는 양방향 바인딩 prop을 선언하는 데 사용될 수 있습니다.
하위 검포넌트
<template>
<h1></h1>
<h1>8</h1>
<button type="button" @click="increaseNumber">increaseNumber</button>
<button type="button" @click="increaseCount">increaseCount</button>
</template>
<script setup lang="ts">
import {defineModel} from "vue";
// "modelValue" prop 선언, 부모에 의해 v-model을 통해 사용됨
const number = defineModel<number>();
// "count" prop 선언, 부모에 의해 v-model:count를 통해 사용됨
const count = defineModel<number>('count', {required: true});
const increaseNumber = () => {
if(number.value) number.value += 1;
}
const increaseCount = () => {
count.value += 1;
}
</script>
상위 검포넌트
<template>
<ChildComponet
v-model="number"
v-model:count="count"
/>
<button type="button" @click="increaseNumber">increaseNumber</button>
<button type="button" @click="increaseCount">increaseCount</button>
</template>
<script setup lang="ts">
import {ref} from "vue";
const number = ref(1);
const count = ref(1);
const increaseNumber = () => {
number.value += 1;
}
const increaseCount = () => {
count.value += 1;
}
</script>
마치며
한 화면에 작업을 맞친 후 컴포넌트로 분리할 때 조금 더 편리하게 v-model을 처리하고 싶어 찾아본 기능입니다.
상위 컴포넌트에서 v-model을 사용한 코드를 하위 컴포넌트으로 이동 후
props로 받아 v-model에 그대로 사용 시 하위 컴포넌트에서는 props를 직접 수정할 수 없기에 에러가 발생합니다.
이럴 경우에 props와 emits을 통해 해결하곤 했습니다.
defineModel을 사용하여 코드를 좀 더 간결하게 하고 상위, 하위의 데이터 전달을 편리하게 하게 할 수 있었습니다.
가끔이지만 상위에서 하위가 아닌 하위에서만 쓰이고 상위에서 읽기만 하고 싶은 데이터가 있을 경우엔
적절하게 defineExpose를 사용해보면 좋을 것 같습니다.
git repository
https://github.com/YoungminShimPMI/data_binding_test
더 많은 기능들…
https://ko.vuejs.org/api/sfc-script-setup