blog

TanStack Query의 staleTime과 gcTime 정리

Front-end / React#TanStack Query#React Query#캐싱#staleTime#gcTime

staleTime과 gcTime(v4까지는 cacheTime)은 이름이 비슷하지만 제어하는 대상이 다르다.

  • staleTime: 데이터를 언제 다시 가져올지
  • gcTime: 아무도 쓰지 않는 데이터를 얼마나 오래 보관할지

staleTime: 언제 다시 가져올까

fetch한 데이터가 fresh(신선) 상태로 유지되는 시간이다.

fetch 완료 ──[fresh: staleTime]──▶ stale

fresh인 동안은 컴포넌트가 마운트되거나 창에 포커스가 돌아와도 다시 요청하지 않는다. stale이 되면 다음 트리거(마운트, 창 포커스, 네트워크 재연결) 때 백그라운드 refetch가 일어난다. 캐시된 데이터를 먼저 보여주고 뒤에서 새 데이터를 받아 교체하는 방식이라, 사용자는 로딩 없이 화면을 본다.

기본값 0

fetch가 끝나는 즉시 stale이 된다. 캐시가 있어도 마운트할 때마다 백그라운드 refetch가 일어난다.

staleTime: 0;              // 기본값. 트리거마다 최신화
staleTime: 5 * 60 * 1000;  // 5분간 fresh. 코드 목록·설정값처럼 잘 안 바뀌는 데이터
staleTime: Infinity;       // 자동 refetch 없음. invalidate나 refetch()로만 갱신

Infinity여도 invalidateQueries나 refetch()를 호출하면 다시 가져온다. "자동으로는 다시 가져오지 않는다"는 뜻이다.

gcTime: 얼마나 오래 보관할까

쿼리를 구독하는 컴포넌트가 모두 언마운트되어 inactive가 된 뒤, 캐시에서 삭제되기까지의 시간이다.

마지막 구독자 언마운트 ──[inactive: gcTime]──▶ 캐시 삭제

구독자가 하나라도 있으면 타이머가 돌지 않는다.

기본값 5분

언마운트 후에도 5분간 캐시를 남겨 둔다. 그 안에 다시 방문하면 저장된 데이터를 즉시 보여주고, stale이라면 백그라운드 refetch도 함께 실행된다. (SSR 서버 쪽에서는 기본값이 Infinity다.)

gcTime: 0;         // inactive 되는 즉시 삭제. 다음 마운트는 항상 로딩부터
gcTime: Infinity;  // 삭제하지 않음. 메모리 사용량 주의

한눈에 비교

항목staleTimegcTime
제어 대상자동 refetch 여부inactive 캐시 보관 기간
기준 시점마지막 fetch 완료마지막 구독자 언마운트
기본값05분
0일 때트리거마다 백그라운드 refetchinactive 즉시 삭제
Infinity일 때자동 refetch 없음삭제하지 않음

자주 쓰는 조합

staleTime 0 + gcTime 5분 (기본)

화면에 있는 동안 트리거마다 최신화하고, 떠났다가 5분 안에 돌아오면 이전 데이터를 즉시 보여준 뒤 갱신한다.

staleTime 5분 + gcTime 5분 이상

잘 바뀌지 않는 데이터. 5분 안에 다시 마운트하면 요청 자체를 보내지 않는다.

staleTime Infinity + gcTime 기본값

"한 번 받으면 명시적으로 무효화하기 전까지 그대로 쓴다". 변경 시점을 앱이 알고 있는 데이터(사용자가 직접 수정하는 설정 등)에 쓰고, 수정 후 invalidateQueries로 갱신한다.

staleTime 0 + gcTime 0

캐시 재사용 없이 마운트할 때마다 로딩부터 새로 받는다. 탭이나 카드를 전환할 때 이전 값이 잠깐이라도 보이면 안 되는 화면에 쓴다.

카드 A 선택 → fetch → 카드 B 선택 (A는 inactive → 즉시 삭제) → 카드 A 재선택 → 로딩 후 fetch

gcTime이 기본값이면 A를 다시 선택했을 때 이전 A 데이터가 먼저 보이고 뒤에서 갱신된다. 이 "이전 데이터 → 새 데이터" 전환 시점에 로컬 상태를 초기화하는 로직이 엮여 있으면, 순서에 따라 엉뚱한 값이 남을 수 있다.

staleTime이 gcTime보다 길면?

문제없는 조합이다. 두 타이머는 서로 다른 구간에서 동작한다. 화면에서 쓰는 동안(active)은 staleTime만 의미가 있고, 아무도 쓰지 않을 때(inactive)는 gcTime이 흐른다. staleTime: Infinity + 기본 gcTime은 공식 문서에도 나오는 흔한 설정이다. 다만 inactive 상태에서 gcTime이 지나 캐시가 지워지면, 남은 staleTime과 관계없이 다음 마운트는 새로 요청한다.

요약

  • 얼마나 자주 다시 가져올지 → staleTime
  • 안 쓰는 데이터를 얼마나 들고 있을지 → gcTime

참고