본문 바로가기
2024 회사 프로젝트

컴포넌트 분리하기

by Kimjoy 2025. 1. 18.

프로젝트 막바지가 되어서 관리자포탈에 대시보드를 완성해야 하는 작업이 생겼다.

회사에서 이렇게 조금 커다란 작업은 나 보다는 선임 연구원한테 맡기는 편이었는데,

선임 연구원이 장장 4일의 예비군을 가게 되었다.

그래서 나에게 맡겨졌다!!

 

먼저 대시보드는 

이런 식으로 항목이 나누어져 있었고, 서버에서 받아온 데이터들을 1, 2, 3, 4에 뿌려주는 구조였다.

 

퍼블리싱과 3,4번만 구현되어 있는 상태여서 나는 1,2번을 구현하면 되는 상황이었고,

4가지 항목이 하나의 vue 파일에 다 보이는 구조였는데

팀장님이 보시더니 

🧑‍💻 코드 이렇게 있으면 안돼 컴포넌트 분리해보자 어떻게 할 수 있을 것 같아?

👩‍💻 1,2,3,4로 나눠서,,?

🧑‍💻 컴포넌트 분리해서 다시 가져오세요

 

이렇게 되어서... 컴포넌트 분리하는 방법부터 찾아 보았다. 

아니 어려운 줄 알았는데 그 부분의 코드로 vue 파일을 만들고 

import 해서 넣으면 끝이었다!

그래서 뭐야~ 엄청 쉽잖아~ 괜히 겁먹었네~ 하면서 다음과 같이 코드를 짰다,

<template>
    <div class="article_1">
      <main_serverStatus/>
    </div>
    <div class="article_2">
      <main_summary/>
    </div>
</template>

<script setup lang="ts">
import main_summary from '@/components/main_summary.vue';
import main_serverStatus from '@/components/main_serverStatus.vue';

그리고 요구사항이 3분마다 api를 호출해서 반환된 값을 1,2에 뿌려주고,

대시보드 화면을 벗어나면 api를 호출하지 않아야 했다.

 

그래서 serverStatus와 summary에서 각각 onMounted, onUnMounted될 때 타이머를 동작시켜서 api를 호출하고, 타이머를 중단시켜서 api 호출을 중지시킬 수 있게 코딩했는데 

팀장님이 이런 경우에는 serverStatus와 summary 내부에서 호출하는게 아니라

serverStatus와 summary를 이용하는 컴포넌트에서 제어할 수 있도록 구현해야한다고 하셨다.

그러니까 api를 호출하는 함수는 serverStatus와 summary에 구현해두고,

타이머를 동작시켜서 api를 호출하는 함수는 dashboard에 구현해 두는 것이다...! 

 

이렇게 되면 생기는 궁금증이 

dashboard.vue에서 main_serverStatus와 main_summary 컴포넌트를 이용하고 있는데

dashboard에서 main_serverStatus와 main_summary 컴포넌트 내부의 함수에 접근할 수 있을까? 였다.

 

그래서 알게된  vue의 기능이 defineExpose()였다!

https://withwltn.tistory.com/28 이 분의 블로그를 보고 따라했는데, 되었다...!!!!!

 

defineExpose()는 

자식 컴포넌트에서 선언된 함수(API)를 부모 컴포넌트에서 직접적으로 호출(import)하여 사용할 수 있는 함수이다.

(출처 : https://withwltn.tistory.com/28 )

 

그래서 자식컴포넌트에서 api를 호출하는 함수를 만들고, defineExpose() 내에 호출할 함수를 적어줬다.

summary같은 경우는 여러가지 서버에 있는 summary를 호출해야했기때문에 

Promise.all()로 묶어줬다.

const selectSummary = async () => {
  await Promise.all([
    *StatusSummary(),
    **Summary(),
    ***Summary(),
    ****Summary(),
    *****Summary(),
  ]);
};

defineExpose({
  selectSummary,
});
const selectServerStatus = async () => {
  try {
    await ***store.getServerStatus();
  } catch (e) {
    notify.error('서버 상태를 불러오는데 실패했습니다.');
  }
};

defineExpose({
  selectServerStatus,
});

그리고 이렇게 만든 selectSummary와 selectServerStatus를 사용하려면

<template>
    <div class="article_1">
      <main_serverStatus ref="serverStatus"/>
    </div>
    <div class="article_2">
      <main_summary ref="summary"/>
    </div>
</template>

<script setup lang="ts">
import main_summary from '@/components/main_summary.vue';
import main_serverStatus from '@/components/main_serverStatus.vue';

import한 컴포넌트에 ref="자식요소에 접근할 ref 선언" 이렇게 추가해주면 된다!

 

그러면 다음과 같이 자식컴포넌트에서 expose한 함수를 사용할 수 있다. 

<script setup lang="ts">
    const summary = ref();
    const serverStatus = ref();
    
    serverStatus.value.selectServerStatus();
    Promise.all([summary.value.selectSummary()]);
    
</script>

 

여기에 3분타이머를 추가하게 되면

onMounted될 때 setInterval()함수에 다음과 같은 

	serverStatus.value.selectServerStatus();
    Promise.all([summary.value.selectSummary()]);


사용할 함수와 시간간격을 넣어서 타이머를 동작시키면 되고, 

onUnMounted될 때 clearInterval()함수를 써서 중단시키면 된다.

 

그리고..... 자식컴포넌트 내에서 또 컴포넌트를 만들 일이 있었는데,,,,,,,

그래서 자식의 자식 컴포넌트에 있는 값을.. 가지고... 또 무언가를 출력해야할 일이 있었는데

이게 진짜 너무 어렵고 어렵고 어려웠다.......

객체.. 안에 배열... 안에 객체..가 있는.... ㅎ.... 다시 생각해도 막막했던...!!!

이건 다음에 포스팅해야지!