Tanstack Query의 staleTime과 gcTime(구 cacheTime) 정리

도현수·2024년 11월 30일
0

프로젝트를 진행하면서 별도의 설정을 하지 않았기 때문에 staleTime 은 0, gcTime 은 5분으로 설정되어 있다. 즉, 데이터가 바로 오래된(stale) 상태로 된다는 뜻인데... 이걸 다루면 사용자 경험 향상에 좀 더 도움이 되지 않을까? 싶어서 설정하며 간단하게 정리했다. 그리고 다루다 보니 계속 헷갈려서 정리해두는 편이 다음을 위해서도 더 좋다고 생각했다.

staleTime

일단 공식문서에서 기본적으로 기억하라고 하는 부분은 다음과 같다.

  • useQueryuseInfiniteQuery 를 사용한 쿼리 인스턴스는 기본적으로 데이터를 낡은(stale)것으로 여김
  • 이거 바꾸려면 전역적으로든 아니면 쿼리별로든 staleTime 옵션을 사용해서 설정해라. staleTime 이 길수록 쿼리가 데이터를 자주 리프레시 하지 않는다.

여기서 잘 봤어야 하는데... staleTime 은 데이터를 몇분 동안 낡았다고 취급할까요? 가 아닌 몇 분 뒤에 이 데이터를 낡았다고 할까요? 임... 즉, staleTime 동안 이 데이터는 신선함. 그리고 데이터가 신선하면 백그라운드에서 refetch 되지 않음.

데이터가 캐시되므로, 신선한 데이터는 여러 페이지 혹은 컴포넌트에서 공유됨. 즉, 빈번한 업데이트가 필요하지 않은 데이터라면 staleTime 을 길게 가져갔을 때 불필요한 네트워크 요청을 줄일 수 있다.

낡은 데이터의 리페치 조건은 다음과 같다.

  • 컴포넌트가 다시 마운트될 때
  • 윈도우가 포커스될 때
  • 네트워크가 다시 연결될 때
  • 추가로 refetchInterval 를 설정할경우 지속적인 자동 페칭이 발생한다.

gcTime(구 cacheTime)

버전 5에서 이름이 변경되었다(참고).
데이터가 사용되지 않고 있을 때(컴포넌트의 언마운트, 데이터가 inactive 상태인 경우) 가비지 콜렉션을 통해 캐시에서 제거되는 시간. 이 시간이 지나면 캐시에서 제거됨. 즉, inactive한 데이터가 캐시에 살아있을 수 있는 기간이라 보면됨. gcTime 은 기본적으로 5분이고, 역시나 gcTime 설정으로 바꿀 수 있음.

동작 정리 (staleTime: 10초, gcTime: 5분 가정)

  1. 데이터의 페칭 및 캐시에 저장
  • 컴포넌트에서 데이터를 페칭함.
  • 페치된 데이터는 캐시에 저장되고, staleTime 동안 신선하게 유지됨.

2.staleTime 이내 (신선한 상태)

  • 만약 해당 컴포넌트가 아니더라도 같은 쿼리를 사용하는 다른 컴포넌트가 있다면, refetch 없이 캐시된 데이터를 사용.
  • gcTime 은 영향x. 데이터가 사용중이기 때문.
  1. staleTime 만료. (10초 지남)
  • 만약 데이터를 어디선가 사용중인 경우: 리페치 조건에 맞는 경우 refetch를 시도해 최신 데이터를 가져옴. 데이터가 사용중이므로 gcTime 에는 영향 x.
  • 데이터를 사용중이지 않은 inactive 상태인 경우: gcTime 의 카운트다운이 시작됨(4분 59초.. 4분 58초...). 그렇게 0까지 카운트다운되면 데이터가 캐시에서 제거됨.
  1. inactive상태로 5분 경과
  • 데이터는 캐시에서 제거됨.
  • 추후 같은 쿼리로 다시 데이터를 가져올 경우, staleTimegcTime 은 다시 10초, 5분으로 설정됨.

실제 적용


회원의 전화번호를 가져오는 페이지에서 직접 적용해보았다. 회원정보는 실시간성이 딱히 중요하지도 않고(전화번호가 실시간으로 바뀌는것도 아니니), 회원 본인이 이 정보를 수정한 경우에만 업데이트 되면 된다(현재 이를 위해 업데이트 후 invalidateQueries 를 호출한다).

현재는 전역으로 staleTime 이 0으로 설정되어 있다. 즉, 데이터가 페치된 직후 바로 "낡았다"라고 판단됨. 따라서 컴포넌트가 언마운트 되었다가 다시 마운트되는 경우(다른 페이지로 갔다가 다시 회원 정보 페이지로 오는 경우 등)에 refetch가 발생하는데, 그 사이에 회원정보가 변하지 않으니 불필요한 refetch라고 할 수 있다.

이런 데이터는 실시간성이 중요하지 않고, 한 번 fetch된 이후로는 변경되기 전까지 그대로 사용해도 상관없는 데이터라고 판단해 staleTime 이 길어도 상관없다고 생각했다. 그렇기에 staleTimeInfinity 로 설정했다.

export default function useGetMemberInfo() {
  const { data } = useSuspenseQuery<{ phoneNumber: string }, AxiosError>({
    queryKey: ["memberInfo"],
    queryFn: () => axiosInstance.get(`/members/me`).then((res) => res.data),
    staleTime: Infinity,
  });

  return { data };
}

해당 설정을 통해 회원 전화번호는 항상 "신선한" 상태이고, 사용자가 변경하지 않는 이상 refetch되지 않는다. 단, 불필요한 데이터 공간 차지를 막기 위해 gcTime 은 아직 5분 이므로, 페이지를 벗어나고 5분 후 다시 들어올 경우엔 전화번호를 다시 fetch 해야한다.

마무리

모호하게만 알고 있던 staleTimegcTime에 대해 본격적으로 알아보며 사용자 경험을 위한 설정까지 생각해볼 수 있었다. 예시에서는 회원 정보에만 적용했지만 다른 부분에도 적용하면서 사용자 경험을 더욱 향상시킬 수 있지 않을까 기대되었고, 이러한 부분을 개발자가 편하게 설정할 수 있도록 한 점이 Tanstack Query의 많은 장점 중 하나가 아닐까 생각된다.

참고

공식문서 1
공식문서 2

0개의 댓글

관련 채용 정보