Contents
see ListVue.js 부모, 자식 컴포넌트 메소드 호출
Vue.js에서 부모-자식 컴포넌트 간 메소드를 호출하는 방법입니다. Props, Events, Refs를 활용하여 컴포넌트 간 통신을 구현합니다.
언제 사용하나요?
- 부모에서 자식 폼 유효성 검사 호출
- 자식에서 부모의 데이터 갱신 요청
- 모달 열기/닫기 제어
- 외부에서 컴포넌트 초기화
부모에서 자식 메소드 호출 (ref)
<!-- 부모 컴포넌트 -->
<template>
<div>
<ChildComponent ref="childRef" />
<button @click="callChildMethod">자식 메소드 호출</button>
</div>
</template>
<script>
import ChildComponent from "./ChildComponent.vue";
export default {
components: { ChildComponent },
methods: {
callChildMethod() {
// ref를 통해 자식 메소드 호출
this.$refs.childRef.childMethod();
// 파라미터 전달
this.$refs.childRef.updateData({ name: "홍길동" });
}
}
};
</script>
<!-- 자식 컴포넌트 -->
<script>
export default {
methods: {
childMethod() {
console.log("자식 메소드 호출됨!");
},
updateData(data) {
this.formData = data;
}
}
};
</script>
Vue 3 Composition API
<!-- 부모 컴포넌트 (Vue 3) -->
<template>
<ChildComponent ref="childRef" />
<button @click="callChild">호출</button>
</template>
<script setup>
import { ref } from "vue";
import ChildComponent from "./ChildComponent.vue";
const childRef = ref(null);
const callChild = () => {
childRef.value.validateForm();
};
</script>
<!-- 자식 컴포넌트 -->
<script setup>
import { ref } from "vue";
const isValid = ref(false);
// 부모가 호출할 메소드를 expose
const validateForm = () => {
// 유효성 검사 로직
isValid.value = true;
return isValid.value;
};
// defineExpose로 외부 노출
defineExpose({
validateForm
});
</script>
자식에서 부모 메소드 호출 ($emit)
<!-- 부모 컴포넌트 -->
<template>
<ChildComponent
@child-event="handleChildEvent"
@update-data="updateParentData" />
</template>
<script>
export default {
methods: {
handleChildEvent(payload) {
console.log("자식에서 이벤트 발생:", payload);
},
updateParentData(data) {
this.parentData = data;
}
}
};
</script>
<!-- 자식 컴포넌트 -->
<template>
<button @click="notifyParent">부모에게 알림</button>
</template>
<script>
export default {
emits: ["child-event", "update-data"],
methods: {
notifyParent() {
// 이벤트 발생
this.$emit("child-event", { message: "Hello!" });
this.$emit("update-data", this.formData);
}
}
};
</script>
Vue 3 Composition API emit
<script setup>
// emit 정의
const emit = defineEmits(["submit", "cancel"]);
const handleSubmit = () => {
emit("submit", { name: "홍길동" });
};
const handleCancel = () => {
emit("cancel");
};
</script>
Props로 함수 전달
<!-- 부모 -->
<template>
<ChildComponent :on-save="handleSave" />
</template>
<script>
export default {
methods: {
handleSave(data) {
console.log("저장:", data);
}
}
};
</script>
<!-- 자식 -->
<template>
<button @click="onSave(formData)">저장</button>
</template>
<script>
export default {
props: {
onSave: {
type: Function,
required: true
}
}
};
</script>
provide/inject (깊은 중첩)
<!-- 조상 컴포넌트 -->
<script setup>
import { provide, ref } from "vue";
const showModal = ref(false);
const openModal = () => { showModal.value = true; };
const closeModal = () => { showModal.value = false; };
// 메소드 제공
provide("modalActions", { openModal, closeModal });
provide("showModal", showModal);
</script>
<!-- 깊은 자손 컴포넌트 -->
<script setup>
import { inject } from "vue";
const { openModal, closeModal } = inject("modalActions");
const showModal = inject("showModal");
</script>
이벤트 버스 대안 (mitt)
// eventBus.js
import mitt from "mitt";
export const emitter = mitt();
// 컴포넌트 A
import { emitter } from "./eventBus";
emitter.emit("user-login", { userId: 1 });
// 컴포넌트 B
import { emitter } from "./eventBus";
import { onMounted, onUnmounted } from "vue";
onMounted(() => {
emitter.on("user-login", handleLogin);
});
onUnmounted(() => {
emitter.off("user-login", handleLogin);
});
권장 패턴
- 부모→자식: ref 또는 props
- 자식→부모: emit 이벤트
- 깊은 중첩: provide/inject
- 형제/무관: Pinia 상태관리