Vue.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 상태관리