React Query: `staleTime`이란 무엇이며 왜 신경 써야 할까요?

발행: (2026년 2월 26일 오후 07:10 GMT+9)
7 분 소요
원문: Dev.to

Source: Dev.to

“Stale”는 무엇을 의미할까요?

냉장고에 있는 우유를 생각해 보세요.

  • 신선한 우유 – 방금 사서 믿고, 생각 없이 바로 마십니다.
  • 상한 우유 – 한동안 방치돼 있었지만, 아직 마실 수 있을 수도 있습니다. 그래도 확인하거나 새 것으로 교체하고 싶을 겁니다.

React Query는 가져온 데이터를 같은 방식으로 다룹니다:

  • 신선한 데이터 – “방금 받아왔으니 다시 가져올 필요가 없어.”
  • Stale 데이터 – “이 데이터가 구식일 수도 있어. 기회가 되면 다시 가져올게.”

Important: Stale 데이터는 캐시에서 사용자에게 표시됩니다. React Query는 로딩 스피너를 보여주지 않고, 백그라운드에서 조용히 다시 가져와서 변경된 경우에만 UI를 업데이트합니다.

The Default Behavior (staleTime = 0)

기본적으로 staleTime0입니다. 이는 데이터가 즉시 캐시되는 순간 React Query가 이를 stale(오래된) 상태로 표시한다는 의미입니다.

따라서 1 초 전에 책 목록을 가져왔더라도, React Query는 다음과 같이 생각합니다: “이 데이터가 오래됐을 수 있으니 다시 가져와야겠어요.”

React Query는 언제 실제로 오래된 데이터를 다시 가져오나요?

다시 가져오기는 특정 트리거에서만 발생합니다:

트리거발생하는 일
Window refocus다른 탭으로 전환했다가 다시 돌아올 때
Component mount이 쿼리를 사용하는 컴포넌트가 마운트/리마운트될 때
Network reconnect오프라인 상태가 되었다가 다시 온라인이 될 때

Common Misconception

“Does moving my mouse trigger a refetch?”

Nope! Only switching away from the tab and coming back (window refocus) does. If you stay on the same tab for 30 minutes, no refetch happens until one of the triggers above occurs.

staleTime 설정: 실제 예시

import { QueryClient, QueryClientProvider } from "@tanstack/react-query";

const queryClient = new QueryClient({
  defaultOptions: {
    queries: {
      staleTime: 1000 * 60 * 5, // 5 minutes
    },
  },
});

function App() {
  return (
    <QueryClientProvider client={queryClient}>
      {/* Your app components */}
    </QueryClientProvider>
  );
}

이 설정으로:

  • 사용자가 페이지를 방문 → React Query가 API에서 책을 가져옵니다.
  • 사용자가 탭을 전환하고 2 분 후에 돌아옴 → 데이터가 여전히 신선합니다. 재요청이 없으며, 결과가 캐시에서 즉시 반환됩니다.
  • 사용자가 7 분 후에 돌아옴 → 데이터가 이제 오래된 상태가 됩니다. React Query가 백그라운드에서 다시 가져오고, 새로운 데이터가 있으면 UI가 업데이트됩니다.

staleTime vs cacheTime (gcTime) — 혼동하지 마세요!

staleTimegcTime (formerly cacheTime)
제어하는 항목데이터가 신선하다고 간주되는 기간사용되지 않는 캐시 데이터가 메모리에 남아 있는 기간
기본값0 (즉시 오래됨)5 minutes
만료 후데이터가 오래된 것으로 표시되고, 다음 트리거 시 다시 가져옴데이터가 가비지 컬렉션되어 캐시에서 제거됨

이렇게 생각해 보세요:

  • staleTime = “이 데이터를 얼마나 오래 신뢰할 수 있나요?”
  • gcTime = “컴포넌트가 사용하지 않을 때 이 데이터를 메모리에 얼마나 오래 보관할까요?”

빠른 시각적 타임라인

Fetch happens at 0:00
|
|-- 0:00 to 5:00  → Data is FRESH (no refetch, served from cache)
|-- 5:00+         → Data is STALE (refetch on next trigger)
|
|-- If no component uses this data for 5 min → cache is GARBAGE COLLECTED

쿼리별 staleTime

개별 쿼리마다 staleTime을 전역 설정이 아닌 개별적으로 지정할 수도 있습니다:

// 이 특정 쿼리는 10분 동안 신선하게 유지됩니다
const { data } = useQuery({
  queryKey: ["books", id],
  queryFn: () => fetchBook(id),
  staleTime: 1000 * 60 * 10, // 10 minutes
});

이는 해당 쿼리 하나에 대해서만 전역 기본값을 재정의합니다.

TL;DR

  • staleTime = 0 (기본값): 데이터가 즉시 오래된 것으로 간주되어 매 트리거마다 다시 가져옵니다.
  • staleTime = 1000 * 60 * 5: 데이터가 5 분 동안 신선하게 유지되어 그 기간 동안 불필요한 API 호출을 방지합니다.
  • 오래된 데이터는 여전히 캐시에서 표시되며 — 재조회는 백그라운드에서 조용히 이루어집니다.
  • 재조회 트리거: 윈도우 포커스 재설정, 컴포넌트 마운트, 네트워크 재연결마우스 움직임은 포함되지 않음.
  • staleTime(신선도)와 gcTime(캐시 수명)은 별개의 개념입니다.

행복한 코딩 되세요!

0 조회
Back to Blog

관련 글

더 보기 »

3단계 반응형 E-commerce 헤더

!Triple-Tier Responsive E-commerce Header의 커버 이미지 https://media2.dev.to/dynamic/image/width=1000,height=420,fit=cover,gravity=auto,format=auto/https%3A%2...