여러 컴포넌트가 같은 queryKey 로 useQuery 호출 가능 — fetch 한 번만 발화, 모든 컴포넌트가 같은 데이터, 캐시 일관성 유지.
Suspense 모드
suspense: true 추가하면 hook 이 use()-모양: isLoading 반환 대신 suspend. Suspense + error boundary 와 결합 → 컴포넌트 body 가 success 경로뿐. 양쪽 최선: TanStack Query 의 캐시 혜택 + Suspense 의 선언적 로딩/에러.
손이 갈 때
같은 데이터 페치하는 컴포넌트 둘 이상 (sidebar + 메인 패널 둘 다 user 객체 필요).
리스트 페이지 → 디테일 페이지 네비게이션 + 리스트 캐시가 re-fetch 없이 디테일 채우길 원함.
안 필요할 때
공유나 revalidation 관심사 없는 one-off 페치.
WebSocket / SSE 로 바뀌는 서버 구동 state (real-time-모양 라이브러리 또는 커스텀 hook).
데이터가 모듈 레벨 상수인 순수 SPA 부트스트래핑.
운영 관심사가 진짜 작업일 때 라이브러리 써. TanStack Query 는 'fetch 에 추가 단계' 가 아냐 — 캐시, 재시도, dedup, refetch 동작에 대한 추상 — 안 그러면 hook 들에 (나쁘게) 재구현하게 될 것. 본인 캐시 map 짜기 시작하는 순간 갈아타.
@tanstack/react-query 설치. 앱 root 에 QueryClient 셋업. useEffect + useState 로 페치하는 컴포넌트를 useSuspenseQuery 쓰는 걸로 리팩토링. 확인: (1) 컴포넌트 더 짧음; (2) 같은 query key 가진 컴포넌트 인스턴스 둘이 네트워크 요청 하나만 트리거; (3) 떠났다 돌아와도 re-fetch 안 함 (기본 stale time 안에서).
Hint
DevTools 의 Network 패널 열어. useState 패턴이면 새 userId 의 매 render 가 fetch 트리거. useSuspenseQuery 면 첫 fetch 캐시; 같은 key 의 후속 방문이 캐시 hit.
Progress
Progress is local-only — sign in to sync across devices.