[react-query] data fetching 상태에 따른 Skeleton (Loading UI) 띄우기

나라·2024년 1월 31일

[PROJECT] SOM

목록 보기
3/3

개요

  • 프로젝트 중 api 요청 서버가 메모리 문제로 며칠 간 긴 pending 상태+500 에러를 뱉어냈다 -> 즉, loading UI 설정 전이라 텅 빈 화면을 계속해서 봐야했다
  • data fetching 중일 때나 request error시 사용자 경험을 고려해 텅 빈 화면 보다는 loading UI Component 를 띄우는 것이 좋다
  • React Query 이용

과정

  • 초반에는 Suspense를 이용해 fallback에 Loading 컴포넌트를 넣는 방식으로 진행했었는데
    fetching 중이거나 요청 실패 시에는 출력되지 않았다
  • useQuery의 fetch 상태값 (isFetched, isFetching... 등) 으로 좀 더 세세하게 처리하기로 결정
  • 일단 공통으로 쓰일 skeleton 컴포넌트 파일을 생성한다

skeleton.tsx


interface Prop {
  width?: string | number
  height?: string | number
}
const Skeleton = ({ width, height }: Prop) => {
  return <li className='skeleton bg-base-200' style={{ width, height }}></li>
}

export default Skeleton
  • width, height 를 Prop으로 전달(옵션)받음

home.tsx

//..중략
  const { data, fetchNextPage, hasNextPage, isSuccess, isFetching, isFetched } =
    useInfiniteQuery<
      PostRes,
      Object,
      InfiniteData<PostRes>,
      [_1: string, _2: number],
      number
    >({
      queryKey: ['home', tab],
      queryFn: getHomeList,
      initialPageParam: 1,
      getNextPageParam: (lastPage) => {
        return lastPage.pageDto.totalPages === 0 ||
          lastPage.pageDto.totalPages === lastPage.pageDto.currentPage
          ? undefined
          : lastPage.pageDto.currentPage + 1
      },
    })
  • 위에서 언급했다시피 useQuery 상태 옵션 값을 이용해 로딩 UI 를 띄울 예정이므로
    isSuccessisFetched 을 구조 분해하여 추출

  • 조건 (삼항) 연산자 이용하여 return

      {isFetched && isSuccess ? ( 
        // data fetch가 끝난 상태고 && 성공했다면?
        <div>
          {data?.pages.map((page, itemIdx: number) => (
            <Fragment key={itemIdx}>
              {page.postList.length < 1 ? ( 
                <p className='resultP'>no Data</p>
              ) : (
                <>
                  <ArticleWrap type='home' list={page.postList} />
                </>
              )}
            </Fragment>
          ))}
          <div ref={ref} style={{ height: 50 }} />
        </div>
      ) : ( 
        // 반대로 fetching 중이거나 error 시
        <>
          <ul className='articleWrap homeArticle'> 
            {new Array(12).fill('').map(() => ( 
        // 12개 요소로 이루어진 배열 생성해 반복문으로 skeleton 컴포넌트 return 
              <Skeleton height={'300px'} />
            ))}
          </ul>
        </>
      )}
    </>

결과

  • 검색 페이지에서도 동일하게 로딩 UI 적용

profile
FE Dev🔥🚀

0개의 댓글