본문 바로가기
React

[React Query] 데이터는 언제 fetch 될까? - (1) Fresh와 Stale 상태

by 맨날개발 2025. 5. 10.
(2) Refetch보러가기

 

 

 

🛫 Fresh와 Stale

Tanstack Query에서는 캐시한 데이터를 Fresh, Stale 상태로 관리를 한다.

 

✅  Fresh

쿼리가 fetch가 되면 Fresh 상태가 되며 해당 상태인 동안에는 쿼리가 신선한것으로 간주하여 해당 데이터를 요청하면 캐시된 데이터를 사용하하고 다시 fetch하지 않는다.

 

ReactQueryDevtools를 통해 확인해보면 아래와 같이 데이터가 초록색인게 Fresh 상태이다.

 

 

✅  Stale

Fresh 상태인 쿼리가 staleTime으로 설정된 시간이 지나면 stale 상태가 된다. 해당 상태는 신선하지 않은 것으로 간주하게 되며, 이 상태인 쿼리를 요청하면 fetch를 통해서 데이터를 가져오도록하게 된다.

 

ReactQueryDevtools를 통해 확인해보면 아래와 같이 데이터가 주황색인게 Stale 상태이다.

 

 

🚓 staleTime과 gcTime

✅  staleTime

staleTime은 fresh 상태인 쿼리가 얼마의 시간이 지난 후 stale 상태로 전환이 될 지를 정하는 시간이다. 기본값은 0으로 0인 경우 fetch 후 즉시 stale 상태가 된다.

 

staleTime은 아래와 같이 설정할 수 있다. 단위는 ms 단위이다. 즉, 아래는 10초로 설정한 것이다.

const { data } = useQuery({
  queryKey: [1],
  queryFn: () => 1,
  staleTime: 1000 * 10,
});

 

모든 쿼리에 staleTime을 설정하고 싶으면 아래와 같이 설졍하면 된다. 이때 개별 쿼리에서 설정된 값에 의해 덮어씌워진다.

const queryClient = new QueryClient({
  defaultOptions: {
    queries: {
      staleTime: 1000 * 1,
    },
  }
})

 

 

✅  gcTime

gcTime은 쿼리가 현재 어느 컴포넌트에서도 사용되지 않는 경우 비활성화된다. 비활성화가 되더라도 데이터는 메모리상에 계속 남아있게 된다. gcTime은 비활성화 된 데이터가 메모리상에서 완전히 제거될 때까지 기다리는 시간이다. 기본값은 5분이다.

 

즉, 쿼리가 사용되지 않게 될 때부터 gcTime 시간만큼의 시간이 흐르면 메모리에서 제거가 된다.

 

gcTime은 아래와 같이 설정할 수 있다. 단위는 ms 단위이다. 즉, 아래는 10초로 설정한 것이다.

const { data } = useQuery({
  queryKey: [1],
  queryFn: () => 1,
  gcTime: 1000 * 10,
});

 

모든 쿼리에 gcTime을 설정하고 싶으면 아래와 같이 설졍하면 된다. 이때 개별 쿼리에서 설정된 값에 의해 덮어씌워진다.

const queryClient = new QueryClient({
  defaultOptions: {
    queries: {
      gcTime: 1000 * 1,
    },
  }
})

 

만약 동일한 키로 다른 gcTime을 설정해서 사용하는 경우, 더 큰 gcTime으로 설정된다.

 

예를 들어 A 컴포넌트에서는 gcTime을 1초로, B 컴포넌트에서는 gcTime을 2초로 설정했을 때 A 컴포넌트만 먼저 렌더링 된다면 gcTime이 1초로 설정된다.

export default function ComponentA() {
  const queryClient = useQueryClient();
  const { data } = useQuery({
    queryKey: [1],
    queryFn: () => 1,
    staleTime: 1000 * 1,
    gcTime: 1000 * 1
  })

  return (
    <>
      <div>Component1</div>
      <div>{data}</div>
    </>
  )
}

export default function ComponentB() {
  const queryClient = useQueryClient();
  const { data } = useQuery({
    queryKey: [1],
    queryFn: () => 1,
    staleTime: 1000 * 1,
    gcTime: 1000 * 2
  })

  return (
    <>
      <div>Component1</div>
      <div>{data}</div>
    </>
  )
}

 

아직 메모리에서 제거되지 않은 상태에서 B 컴포넌트를 렌더링하면 gcTime은 2초로 변경된다. 이후 B 컴포넌트가 제거되고 A 컴포넌트가 렌더링되더라도 설정은 그대로 더 큰 시간인 2초를 따른다.

이 내용은 staleTime과 다른 부분이다. staleTime은 시간 크기와 상관없이 현재 요청한 쿼리의 시간으로 교체된다.

 

 

✅ staleTime과 gcTime과의 관계

쿼리가 비활성화가 되더라도 staleTime은 누적해서 계산된다. 예를들어 staleTime이 10초이고, 9초가 지난 시점에 비활성화되었다면 1초후 데이터는 stale 상태가 된다.

 

stale 상태이면 쿼리를 fetch할 것이기 때문에 굳이 gcTime이 없이 staleTime이 되면 데이터를 삭제하면 되지 않을까?

 

stale 상태인 쿼리의 역할을 잘 알지 못했을 때 위와 같은 의문을 가졌었다.

 

stale 상태가 되어도 메모리상에서는 계속 존재하게 된다. 그 이유는 쿼리가 fetch되는 동안 보여줄 데이터이기 때문이다. stale 될때 메모리에서 제거가 된다면 화면에는 해당 데이터가 표시되지 않아 빈 화면만 보여지게 된다.

 

이를 방지하고 사용자 경험을 향상시키기 위해 fetch 동안 stale 상태인 데이터를 보여주고 fetch가 완료되면 교체하는 방식을 사용한다.

 

 

🙄 결론

staleTime은 얼마나 자주 최신 데이터를 불러올지를 결정하는 것.

gcTime은 사용되지 않는 데이터를 얼마나 오랫동안 메모리상에 저장할지를 결정하는 것.

stale 상태의 데이터를 활용하려면 gcTime을 staleTime보다 크게 설정하는 것이 좋다. 그래야 fetch 동안에 로딩 상태가 아닌 데이터를 보여줄 수 있기 때문이다.