계발하는 개발자

[Vue.js] 자식컴포넌트에서 부모컴포넌트로 데이터 전달 본문

💻 Frontend/Vue.js

[Vue.js] 자식컴포넌트에서 부모컴포넌트로 데이터 전달

dev_genie 2023. 9. 4. 08:17
부모컴포넌트 ➡️ 자식컴포넌트로의 데이터 전달은 props로 가능하다.
그러면 그 반대는 어떻게?
자식컴포넌트 ➡️ 부모컴포넌트로의 데이터 전달은 $emit을 이용한 방법이 있다.

아래같은 경우를 살펴보자.

<template>
	블라블라 코드
    <DetailComp v-if="showDt" :style="compStyle" @close-detail="closeDetail"/>
    블라블라 코드 
</template>

<script>
// 자식 컴포넌트
import DetailComp from './DetailComp.vue';

export default {
    name: 'GoodsComp',
    components: {
        DetailComp,
    },
    data() {
        return {
            showDt: false,
        };
    },
    computed: {
        // 상세페이지 조건부 렌더링
        compStyle() {
            return {
                visibility: this.showDt ? 'visible' : 'hidden',
                opacity: this.showDt ? 1 : 0,
                transition: this.showDt ? '0.3s ease' : '0s ease', 
            };
        },
    },

DetailComp라는 자식컴포넌트를 GoodsComp라는 부모컴포넌트가 감싸고 있다.

DetailComp는 showDt가 true인 상황에서만 렌더링될 수 있다.

DetailComp는 상품 li 클릭시에 호출되는 getData함수가 실행됐을 때 true가 된다.

<li v-for="a in v" :key="a.name" @click.prevent="getData(a)" v-on:mouseover="handleMouseOver" v-on:mouseleave="handleMouseLeave">
    <div class="ui-prod-bx">
</li>
                                                    
methods: {
    getData(pm) {
        // [ 스토어 전역변수에 업데이트! ]
        // 기본정보 데이터
        store.state.dtname = pm['name'];
        store.state.dtimg = pm['img'];
        store.state.dtoprice = pm['oprice'];
        store.state.dtdprice = pm['dprice'];
        store.state.dtcolor = pm['color'];
        store.state.dtsize = pm['size'];
        // 썸네일 데이터
        store.state.dtsumimg2 = pm['sumimg2'];
        store.state.dtsumimg3 = pm['sumimg3'];

        // 디테일박스 열기
        this.showDt = true;
},

그리고 당연하게 showDt는 디테일박스가 닫혔을때 false 처리 되어야 한다.

그런데, DetailComp(자식)의 v-if 조건값을 GoodsComp(부모)만 참조하고 있는 상황이므로 자식컴포넌트에서 아래와 같이 자식컴포넌트에서 부모컴포넌트의 데이터를 props로 전달받아서 임의로 조작할 수 없는 문제가 생긴다.

<!-- 부모 컴포넌트 -->
<DetailComp v-if="showDt" :style="compStyle" :detData="showDt" />

<!-- 자식 컴포넌트 -->
export default {
  props: ['detData'],
  methods: {
    closeDetail() {
        // 상품 디테일박스 & 상품 옵션 박스 & 최종 결제가 박스 닫힘
        $(".dtfinal_bx").css("display", "none");
        $(".dttot_bx").css("display", "none");
        // 색상 선택후 바로 닫기버튼 클릭시 텍스트 초기화
        $(".option_color > span").text("색상 옵션을 선택해 주세요.");

        // 디테일박스 닫기
       this.detData = false;
    },
  },

 

이런 경우에 $emit이 필요한데, 왜냐하면 props로 받아온 데이터는 일반적으로 해당 값을 자식컴포넌트에 셋팅하는 개념이지, 자식컴포넌트에서 값을 수정해서 내보내는 개념이 아니기 때문이다.

 

위 코드를 $emit을 이용하여 바꾸면 아래와 같이 바꿀 수 있다.

<!-- 자식 컴포넌트 -->
<div class="dtbtn clbtn" @click.prevent="closeDetail">
    <a href="#">
        CLOSE
        <i class="fa-solid fa-xmark"></i>
    </a>
</div>

closeDetail() {
    // 상품 디테일박스 & 상품 옵션 박스 & 최종 결제가 박스 닫힘
    $(".dtfinal_bx").css("display", "none");
    $(".dttot_bx").css("display", "none");
    // 색상 선택후 바로 닫기버튼 클릭시 텍스트 초기화
    $(".option_color > span").text("색상 옵션을 선택해 주세요.");

	// 부모 컴포넌트로 데이터 전달
    this.$emit('close-detail');
},

<!-- 부모 컴포넌트 -->
<DetailComp v-if="showDt" :style="compStyle" @close-detail="closeDetail"/>

export default {
    name: 'GoodsComp',
    components: {
        DetailComp,
    },
    methods: {
            getData(pm) {
                // [ 스토어 전역변수에 업데이트! ]
                // 기본정보 데이터
                store.state.dtname = pm['name'];
                store.state.dtimg = pm['img'];
                store.state.dtoprice = pm['oprice'];
                store.state.dtdprice = pm['dprice'];
                store.state.dtcolor = pm['color'];
                store.state.dtsize = pm['size'];
                // 썸네일 데이터
                store.state.dtsumimg2 = pm['sumimg2'];
                store.state.dtsumimg3 = pm['sumimg3'];

                // 디테일박스 열기
                this.showDt = true;
            },
            closeDetail() {
                this.showDt = false;
            },
    }

 

자식컴포넌트에서 $emit을 이용하여 부모컴포넌트에서 만들어 놓은 이벤트를 호출한다.

그리고 호출시 부모컴포넌트에서 연결한 closeDetail 함수가 실행되게 되는 로직이다.

이렇게 하면 닫기버튼을 클릭했을 때 closeDetail 함수가 호출되고 showDt 값이 다시 false 처리되면서 디테일박스가 닫히게 된다.

 

👍 결과 화면 👍

이제 의도했던 기능이 잘 구현된다 :-D !!

LIST
profile

dev_genie

@dev_genie

포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!