본문 바로가기

Frontend

React Query에서 두 번째 요청이 더 빠르게 느껴지는 이유

컴포넌트를 클릭하면 데이터를 요청하는 UI를 구현하면서 같은 컴포넌트를 클릭해도 첫 번째 클릭과 두 번째 클릭의 체감 속도가 완전히 다르다는 점을 알게 되었다.

  • 첫 번째 더블클릭: 로딩 스피너만 돌고, 로딩 스피너 뒤의 화면은 텅 비어 있다가 나중에 데이터 등장
  • 같은 항목을 다시 더블클릭: 스피너는 계속 도는데, 스피너 뒤에 이전 데이터가 먼저 보이고 곧 최신 데이터로 갱신됨

 

React Query의 상태: isLoading vs isFetching

React Query는 로딩 단계를 두 가지로 나눈다.

  • isLoading: 캐시에 데이터가 없어 처음 로딩 중이다.
  • isFetching: 데이터는 있지만, 최신화를 위해 백그라운드 요청 중이다.

 

첫 번째 요청에서의 상태

isLoading: true
isFetching: true

 

화면에 보여줄 데이터가 없고, 지금 처음 데이터를 가져오는 중이다.

따라서 UI는 이렇게 된다.

  • 데이터 없음
  • 스피너만 보임 → 초기 하드 로딩(hard loading)

 

두 번째 요청에서는 이렇게 바뀐다

isLoading: false
isFetching: true

 

화면에 보여줄 캐시 데이터는 있고, 동시에 최신화를 위해 다시 요청 중이다.

  • isLoading은 ‘화면이 비는 상황’에서만 true
  • isFetching은 ‘백그라운드 요청 여부’일 뿐

UI는 이렇게 변한다.

  • 이전 데이터가 즉시 렌더됨
  • 뒤에서만 isFetching=true로 새 데이터를 받아 갱신

 

두 번째 요청이 “훨씬 빠르게 느껴지는” 이유

 

React Query는 원래 이런 전략을 사용한다. 캐시가 있으면 일단 보여주고(stale), 백그라운드에서 최신화(revalidate)를 수행한다.

즉, HTTP 요청이 빨라진 게 아니라 UI 렌더링 순서가 달라져서 빨라진 것처럼 느껴지는 것이다.

 

그러면 언제 이 빠름 효과가 사라질까?

gcTime(=cacheTime)이 지나면 캐시가 삭제된다.

  • 기본 gcTime: 5분
  • 이 시간이 지나면 캐시는 가비지 컬렉션됨

다시 클릭하면? 캐시 없음 → isLoading=true → 느리게 느껴짐

즉, 처음 클릭하는 것처럼 동작이 돌아간다.

 

staleTime이 0이어도 캐시는 남아 있을까? YES! staleTime=0은 항상 stale 처리하여 refetch한다”는 의미지 캐시를 없앤다는 뜻이 아니다.

 

참고

const { data, isLoading, isFetching } = useQuery({
  queryKey: ['user', userId],
  queryFn: fetchUser,
  staleTime: 0,                 // 즉시 stale 처리
  gcTime: 5 * 60 * 1000,        // 캐시는 5분 보관
});