Tanstack Query를 활용하여 페이지네이션 기능을 구현하던 중, 페이지를 변경할 때마다 레이아웃이 깨어지거나 화면이 깜빡이는 현상이 발생하였다.
이는 사용자 경험을 심각하게 저해하는 요소로 확인되었으며, 실제 크롬 Lighthouse 측정 결과 CLS(Cumulative Layout Shift)
점수가 0.277
로 나타나 웹 접근성과 퍼포먼스 기준인 0.1
이하를 크게 초과한 상태였다.
해당 문제는 useQuery
훅에서 queryKey
가 변경됨에 따라 데이터를 다시 fetch하는 과정에서 발생하였다.
기존 데이터를 유지하지 않고 새 데이터를 받아오기 전까지 로딩 스피너만 표시되었기 때문에, 순간적으로 빈 영역이 생기면서 화면이 깜빡이고 CLS 수치가 상승한 것이다.
이를 해결하기 위해 placeholderData
와 keepPreviousData
옵션을 적용하였다.
<aside> 💬
두 옵션은 무슨 역할을 하는가?
placeholderData
는 새로운 데이터를 받아오기 전까지 임시 데이터를 보여주는 역할을 한다.keepPreviousData
는 기존 페이지의 데이터를 유지시켜주는 옵션으로, 로딩 중에도 기존 데이터가 사라지지 않게 해준다.
</aside>[참고] placeholderData
가 적용된 개선된 코드
import { keepPreviousData, useQuery } from '@tanstack/react-query';
export default function useDefaultQuery(key: any[], url: string) {
const { data, isPending, isError, error, isFetching, isPlaceholderData } =
useQuery({
queryKey: key,
queryFn: () => getDefaultFetcher(url, ApiType.INTERNAL),
placeholderData: keepPreviousData,
});
if (isError) toast.error('데이터 조회에 실패하였습니다.');
return { data, isPending, isError, error, isFetching, isPlaceholderData };
}
추가적으로 CLS 문제를 방지하기 위해 컴포넌트의 최소 높이(min-height)나 넓이(min-width)를 고려하였다.
렌더링 경계 요소에 명시적으로 크기를 지정하지 않으면, 데이터가 로드되지 않은 순간에 레이아웃이 흔들릴 수 있기 때문이다.
마지막으로, 형제 요소 간의 충돌도 고려하여 전체 레이아웃 안정성을 확보하였다.