
프론트엔드에서 페이지 로딩 시간은 사용자 경험에 큰 영향을 미치는 핵심 요소이다.
2017년 Google은 모바일 웹 페이지 로딩 속도와 이탈률의 관계를 조사한 결과를 발표했다.

출처: Find out how you stack up to new industry benchmarks for mobile page speed
5초가 넘어가면 이탈률이 90%, 6초 이후에는 100%를 초과하는 것으로 나타났다.
이는 곧 페이지 로딩 속도가 사용자 유지에 직접적인 영향을 미친다는 것을 의미한다.
이번 글에서는 실제 프로젝트에서 TanStack Query의 prefetchQuery를 활용해 페이지 로딩 속도를 개선한 경험을 정리해보겠다.
prefetchQuery는 데이터를 미리 가져와 캐싱해두는 기능을 제공한다. 이를 통해 페이지 전환 시 네트워크 지연 없이 즉시 콘텐츠를 렌더링할 수 있다.
await queryClient.prefetchQuery({ queryKey, queryFn })
// queryClient의 옵션으로 queryFn을 정의했다면 아래도 가능
await queryClient.prefetchQuery({ queryKey })
prefetchQuery는 fetchQuery와 다르게 결과를 반환하지 않으며 에러를 던지지도 않는다. 단지 데이터를 미리 불러와 캐시에 저장해두는 역할만 수행한다.
이번 프로젝트에서는 라우팅 직전에 데이터를 미리 받아오도록 구현했다.
Button 컴포넌트의 onMouseEnter 이벤트가 발생하면 prefetchQuery가 실행되며 사용자가 버튼을 클릭하기 전에 이미 데이터가 준비된 상태가 된다.
이때 staleTime을 반드시 지정해야 한다. staleTime이 없으면 데이터가 즉시 stale 상태로 인식되어 매번 새로 데이터를 가져오게 된다. 또한 라우팅 시에도 캐싱된 데이터를 활용하지 못하게 된다.
const onMouseEnter = () => {
queryClient.prefetchQuery({
queryKey: [CUSTOM_STICKER.GET_CUSTOM_STICKER_BY_ID, item.id.toString()],
queryFn: () => getCustomStickerById(item.id.toString()),
staleTime: 1000 * 60, // 캐시가 1분동안 유효
});
};
...
<Button
...
onMouseEnter={onMouseEnter}
>
...
</Button>
useQuery에서도 동일하게 staleTime을 지정해야 한다. 그렇지 않으면 캐싱된 데이터를 인식하지 못하고 매 요청마다 새롭게 데이터를 가져오게 된다.
export const useGetCustomStickerById = (id: string | null) => {
return useQuery({
queryKey: [CUSTOM_STICKER.GET_CUSTOM_STICKER_BY_ID, id],
queryFn: () => getCustomStickerById(id as string),
enabled: !!id,
select: (data) => data.result,
staleTime: 1000 * 60,
});
};


Network 환경을 4G로 설정하여 비교 테스트를 진행했다.
적용 이전에는 페이지 전환 시 로딩 스피너가 잠깐 표시되었지만 prefetchQuery를 적용한 이후에는 미리 캐싱된 데이터를 즉시 불러오기 때문에 로딩 스피너 없이 바로 콘텐츠가 렌더링되는 것을 확인할 수 있었다.
이를 통해 네트워크 속도가 제한된 환경에서도 사용자는 지연 없이 즉시 화면을 볼 수 있는 경험을 하게 된다.
평소에 미루고 미루던 prefetchQuery를 이용한 성능 개선을 해보았다. 가장 고민이 됐던 부분은 “staleTime은 어느 정도가 적당할까?”였다. 나름의 기준으로 상세 보기의 경우 1분으로 잡고 목록 조회의 경우는 5분으로 잡았다. 다른 프로젝트에서도 캐싱 전략을 유용하게 써먹어야겠다.
그동안 미루고만 있던 prefetchQuery를 활용한 성능 개선 작업을 드디어 진행했다.
이번에 가장 고민이 되었던 부분은 바로 “staleTime을 어느 정도로 설정하는 것이 적절할까?”였다.
고민 끝에 나름의 기준을 세웠다.
staleTime을 1분으로 설정이번 경험을 통해 캐싱 전략이 사용자 체감 속도를 확실하게 개선할 수 있다는 것을 느꼈다. 앞으로 다른 프로젝트에서도 이 캐싱 전략을 적극적으로 활용해 봐야겠다.