data fetching 중일 때나 request error시 사용자 경험을 고려해 텅 빈 화면 보다는 loading UI Component 를 띄우는 것이 좋다Suspense를 이용해 fallback에 Loading 컴포넌트를 넣는 방식으로 진행했었는데useQuery의 fetch 상태값 (isFetched, isFetching... 등) 으로 좀 더 세세하게 처리하기로 결정
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
//..중략
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 를 띄울 예정이므로
isSuccess와 isFetched 을 구조 분해하여 추출
조건 (삼항) 연산자 이용하여 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>
</>
)}
</>

