yamoo9 / likelion-FEQA

질문/답변 — 프론트엔드 스쿨, 멋사
29 stars 9 forks source link

[LAB-5] fireStore에서 데이터 받아올때, Suspense 적용 이슈 #187

Closed seoohyeon closed 1 year ago

seoohyeon commented 1 year ago

질문 작성자

김서현

문제 상황

Mar-22-2023_00-56-52

[ 데이터 가져오는 파일 ] image image image

프로젝트 저장소 URL

https://github.com/React-Project-lab5/React-Project-lab5
develop브랜치

image

환경 정보

yamoo9 commented 1 year ago

문제에 대한 정확한 진단

fireStore에서 데이터를 읽어와서 그런지, 팝업창 UI 랜더링이 일부 늦습니다.

당연합니다. 서버에서 데이터를 가져오려면 시간이 소요됩니다.

이 팝업창은 페이지가 아니라 컴포넌트이고, 해당 모달창은 이벤트, useState, boolean을 이용하여 open, close 됩니다. 야무쌤이 언급하신 Suspense를 적용해보려 했으나, 페이지가 아니라서 어디를 감싸서 적용해야 하는지 몰라 이슈를 남깁니다.

Suspense의 사용 목적은 데이터를 불러오는 동안 대체할 UI(컴포넌트)를 제공하는 것입니다. Suspense를 사용한다고 해서 UI 축이 움직이는 것을 해결할 수 있는 것은 아닙니다. 이 문제는 CSS 레이아웃 기술로 해결해야 합니다.

문제 해결 방법

CSS 레이아웃

Suspense 사용 없이 CSS 레이아웃을 조정해 모달 다이얼로그 UI의 Y축이 움직이지 않도록 설정한 경우 다음과 같이 렌더링 됩니다.

모달 다이얼로그 UI의 Y축이 움직이는 이유는 높이 설정이 없었기 때문입니다. 다음과 같이 레이아웃 설정을 추가합니다.

MapContainer.module.scss

.mapContainer {
  height: 290px;
  // ...
}

Modal.module.scss

.showUsers {
  height: 141px;
  // ...
}

그리고 users 데이터에 아이템이 추가되는 동안 사용자에게 대체해 보여줄 UI를 제공해야 합니다. 아래 예시 코드는 showUsers 코드를 조건에 따라 처리되도록 수정한 것입니다. users 배열에 아이템이 없을 경우, "로딩 중..."이 화면에 표시되게 됩니다.

ReadMeetings.tsx

const showUsers =
  users.length > 0 ? (
    users.map((value, index) => (
      <div key={index} className={classes.showUsers}>
        <MapReading mapPosition={value.mapData} />
        <span>{value.title}</span>
        <span>{value.addres}</span>
        <span>{value.detail}</span>
        <span>{value.cardData.slice(0, 15)}</span>
        <span className={classes.lastSpan}> {value.cardData.slice(16)}</span>
      </div>
    ))
  ) : (
    <div
      style={{
        height: 141,
        display: 'flex',
        justifyContent: 'center',
        alignItems: 'center',
      }}
    >
      로딩 중...
    </div>
  );

Suspense 활용

Suspense를 사용하려면 공식 문서에서 안내하는 대로 사용해야 합니다.

예를 들어 비동기로 불러올 컴포넌트를 별도 파일로 작성해야 합니다.

import { MapReading } from '@/utils/MapReading';

export default function ShowUsers({ users, classes }) {
  return users.map((value, index: number) => (
    <div key={index} className={classes.showUsers}>
      <MapReading mapPosition={value.mapData} />
      <span>{value.title}</span>
      <span>{value.addres}</span>
      <span>{value.detail}</span>
      <span>{value.cardData.slice(0, 15)}</span>
      <span className={classes.lastSpan}> {value.cardData.slice(16)}</span>
    </div>
  ));
}

그리고 lazy 함수를 사용해 비동기 방식으로 불러오도록 설정해야 합니다.

const ShowUsers = React.lazy(() => import('@/components/ShowUsers'));

마무리로 Suspense 컴포넌트를 사용해 아래와 같이 구성하고, 대체(fallback) UI를 제공합니다.

<React.Suspense fallback={<div>로딩 중...</div>}>
  <ShowUsers users={users} classes={classes} />
</React.Suspense>