[React] TanStack Query(React Query) 깊게 파고들기 : useQuery와 캐시 생명주기의 모든 것

2026. 1. 15. 05:29·💻 개발/🦕 React
728x90
반응형

| 서론

안녕하세요, 팡일입니다!


이번 포스팅에서는 TanStack Query(이하 React Query)의 가장 핵심적인 훅인 useQuery를 깊이 있게 살펴보려고 합니다.

 

단순히 “데이터를 가져오는 방법”을 넘어서, React Query가 내부적으로 데이터를 어떻게 관리하는지, 그리고 우리가 어떤 옵션들을 통해 그 동작을 제어하고 애플리케이션을 최적화할 수 있는지를 실제 코드와 함께 차근차근 정리해보겠습니다.

 

 

 

| 들어가며: React Query는 단순한 데이터 페처가 아니다

많은 React 개발자들이 서버 데이터를 가져오기 위해 useEffect와 useState를 조합한 패턴을 사용해본 경험이 있을 것입니다.

 

하지만 이 방식에는 늘 같은 문제가 따라옵니다.

  • 로딩 상태 관리
  • 에러 상태 처리
  • 불필요한 API 호출
  • 캐싱 로직 구현

이 모든 것들이 반복적인 보일러플레이트 코드로 쌓이게 됩니다.

 

 

React Query는 바로 이 서버 상태(Server State)를 “가져오는 것(fetch)”이 아니라, “관리(manage)”하기 위해 탄생한 라이브러리입니다.

 

그리고 이 관리의 핵심에는 바로 캐시(Cache)가 있습니다.

  • 한 번 가져온 데이터를 캐시에 저장하고
  • 언제 재사용할지
  • 언제 다시 서버에 요청할지

이 모든 판단을 React Query가 대신 처리해줍니다.

그 결과 우리는 비즈니스 로직과 UI에 더 집중할 수 있게 됩니다.

 

 

 

| 개발 환경 설정 및 Devtools

React Query를 사용하기 위한 최소한의 개발 환경 설정입니다.
(현재 프로젝트에서는 이미 설정이 완료되어 있다고 가정합니다.)

 

1) 패키지 설치

먼저 필요한 패키지들을 설치합니다.

  • axios : HTTP 통신을 위한 클라이언트
  • json-server : 목업 API 서버
npm install @tanstack/react-query @tanstack/react-query-devtools axios
npm install -D json-server

 

 

 

2) json-server로 API 서버 실행하기

프로젝트 루트에 위치한 db.json 파일이 우리의 간단한 데이터베이스 역할을 합니다.

{
  "posts": [
    {
      "id": "1",
      "title": "블로그에 오신걸 환영합니다. 수정되었습니다."
    },
    {
      "id": "2",
      "title": "react 강좌 첫 번째 시간"
    }
  ]
}

 

package.json의 scripts에 아래와 같이 추가하면 npm run server 명령어로 API 서버를 실행할 수 있습니다.

// package.json
"scripts": {
  "server": "json-server --watch db.json"
}

 

 

 

3) QueryClient 설정 및 ReactQueryDevtools

React Query의 모든 기능은 QueryClient를 통해 제공됩니다.

 

따라서 애플리케이션 최상단에서 QueryClientProvider로 앱을 감싸주어야 합니다.

// src/App.jsx

import TodoList from "./TodoList";
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
import { ReactQueryDevtools } from "@tanstack/react-query-devtools";

// QueryClient는 캐시와 쿼리 전반을 관리하는 핵심 객체입니다.
const queryClient = new QueryClient();

function App() {
  return (
    <QueryClientProvider client={queryClient}>
      <TodoList />
      <ReactQueryDevtools initialIsOpen={false} />
    </QueryClientProvider>
  );
}

export default App;

 

특히 ReactQueryDevtools는 쿼리 캐시의 상태 변화를 실시간으로 시각화해주는 강력한 도구이므로, 개발 중에는 반드시 활성화해두는 것을 추천합니다.

 

 

 

| 캐시의 생명주기: Fresh, Stale, Inactive, 그리고 GC

React Query의 캐시 데이터는 명확한 생명주기(lifecycle)를 가집니다.

 

Devtools에서는 색상으로 현재 상태를 한눈에 확인할 수 있습니다.

  • Fresh (신선한 상태, 초록색)
    : 데이터가 최신이라고 간주되는 상태
    → 이 상태에서는 재요청이 발생하지 않습니다.
  • Stale (오래된 상태, 빨간색)
    : 데이터가 오래되었다고 판단된 상태
    → 화면에는 캐시 데이터를 사용하지만, 특정 조건에서 백그라운드 refetch가 발생합니다. (이것이 바로 stale-while-revalidate 전략입니다.)
  • Inactive (비활성 상태, 회색)
    : 해당 쿼리를 사용하는 컴포넌트가 모두 언마운트된 상태
    → 일정 시간이 지나면 GC 대상이 됩니다.
  • Garbage Collected (GC)
    : 캐시에서 완전히 제거된 상태

 

 

 

| 생명주기를 제어하는 useQuery 핵심 옵션 (1) – 시간 설정

이 캐시 생명주기는 옵션을 통해 직접 제어할 수 있습니다.

 

1) staleTime

  • 데이터가 Fresh 상태로 유지되는 시간
  • 기본값: 0
staleTime: 0

 

이는 데이터를 가져오자마자 즉시 Stale 상태가 된다는 의미입니다.

 

만약 데이터 변경이 잦지 않다면 다음과 같이 설정할 수 있습니다.

useQuery({
  queryKey: ["posts"],
  queryFn: fetchPosts,
  staleTime: 1000 * 60 * 5, // 5분
});

→ 불필요한 API 호출을 크게 줄일 수 있습니다.

 

 

2) gcTime

  • Inactive 상태의 데이터가 캐시에 유지되는 시간
  • 기본값: 1000 * 60 * 5 (5분)
staleTime = 데이터의 유통기한
gcTime     = 냉장고 정리 주기
  • gcTime은 항상 staleTime보다 같거나 길게 설정하는 것이 일반적입니다.
  • 그래야 캐시를 재활용할 수 있습니다.

 

 

 

| 생명주기를 제어하는 useQuery 핵심 옵션 (2) – 자동 재요청

React Query는 사용자 경험을 위해 특정 상황에서 자동으로 refetch를 수행합니다.

  • refetchOnWindowFocus (기본값: true)
  • refetchOnMount (기본값: true)
  • refetchOnReconnect (기본값: true)

필요하지 않다면 개별적으로 끌 수 있습니다.

useQuery({
  queryKey: ["posts"],
  queryFn: fetchPosts,
  refetchOnWindowFocus: false,
  refetchOnMount: false,
});

 

 

 

 

| 그 외 유용한 useQuery 옵션들

  • enabled
    → 조건부 쿼리 실행 (버튼 클릭 후 실행 등)
  • retry
    → 실패 시 재시도 횟수 (기본값: 3)
  • select
    → 서버 응답 데이터를 가공해서 전달
  • placeholderData
    → 로딩 중 보여줄 임시 데이터

 

 

 

| 실전 예제: TodoList.jsx 코드 분석

const { data, refetch } = useQuery({
  queryKey: ["pstList"],
  queryFn: async () => {
    const response = await fetch("http://localhost:3000/posts");
    return await response.json();
  },
});

 

1) 동작 흐름

  1. 컴포넌트 마운트
  2. 캐시 없음 → 서버 요청
  3. 데이터 수신
  4. staleTime이 0 → 즉시 Stale
  5. 포커스 복귀 시 자동 refetch

 

 

2) 최적화 제안

staleTime: 1000 * 60 // 1분

→ 실시간성이 필요 없다면 API 호출 수를 크게 줄일 수 있습니다.

 

 

 

| 맺음말

이번 포스팅에서는 useQuery의 핵심인 캐시 생명주기와 옵션들을 살펴보았습니다.

 

React Query를 제대로 활용하기 위한 열쇠는 “언제 데이터를 다시 가져올 것인가”를 이해하는 것입니다.

 

728x90
반응형

'💻 개발 > 🦕 React' 카테고리의 다른 글

[React] React + Vite + TS + Firebase Hosting + Github Action 구축하기  (0) 2026.01.18
[React] TanStack Query(React Query) 활용하기 - useMutation으로 데이터 생성·수정·삭제 마스터하기  (0) 2026.01.15
[React] 코드 스플리팅을 적용했을 뿐인데, 초기 로딩이 줄어들었습니다  (0) 2025.12.27
[React] public 이미지에서 import 구조로 (이미지 최적화 개선기)  (1) 2025.12.27
[React] target="_blank" ESLint 경고의 의미와 해결 방법 (react/jsx-no-target-blank)  (0) 2025.12.27
'💻 개발/🦕 React' 카테고리의 다른 글
  • [React] React + Vite + TS + Firebase Hosting + Github Action 구축하기
  • [React] TanStack Query(React Query) 활용하기 - useMutation으로 데이터 생성·수정·삭제 마스터하기
  • [React] 코드 스플리팅을 적용했을 뿐인데, 초기 로딩이 줄어들었습니다
  • [React] public 이미지에서 import 구조로 (이미지 최적화 개선기)
pangil_kim
pangil_kim
기록을 통해 지속적인 성장을 추구합니다.
  • pangil_kim
    멈추지 않는 기록
    pangil_kim
  • 전체
    오늘
    어제
  • 📝 글쓰기
      ⚙️ 관리

    • 분류 전체보기 (405) N
      • 💻 개발 (176) N
        • ※ 참고 지식 (9)
        • 🦕 React (13)
        • 🎩 Next.js (25)
        • 📘 TypeScript (4)
        • 📒 JavaScript (8)
        • 🟩 Node.js (7)
        • 📀 MySQL (24)
        • 🌸 Spring Boot (5)
        • 👷 SveleteKit (24)
        • 🩵 Flutter (11)
        • 🌀 Dart (2)
        • 🌈 CSS (5)
        • 🔸Git (1)
        • 🔥 Firebase (4)
        • 🧑🏻‍💻 코테 (29) N
        • 🕸️ 알고리즘 (4)
        • 🌤️ AWS (1) N
      • 📋 프로젝트 (4) N
        • ☄️ 트러블 슈팅 (2) N
        • 🧑🏻‍💻 서비스 소개 (2)
      • ✍🏻 회고 (52) N
        • ☀️ 취준일지 (6) N
        • 🍀 우테코 (32)
        • 👋 주간회고 (1) N
      • 📰 정보 공유 (12)
      • 🧑🏻‍💻 개발자라면? (1)
      • 🏫 한동대학교 (153)
        • Database (15)
        • Software Engineering (18)
        • EAP (22)
        • 일반화학 (26)
        • 25-1 수업 정리 (19)
        • Computer Networking (36)
        • OPIc (2)
        • 미술의 이해 (15)
  • 최근 글

  • 인기 글

  • 태그

    날솟샘
    우테코 8기
    typeScript
    예배
    프론트엔드
    computer networks and the internet
    GLS
    어노인팅
    묵상
    csee
    웹개발
    고윤민교수님
    우테코
    데이터베이스
    프리코스
    전산전자공학부
    우아한테크코스
    찬양
    CCM
    설교
    컴네
    한동대학교
    웹 프론트엔드 8기
    QT
    날마다 솟는 샘물
    네트워킹
    FE
    주일
    글로벌리더십학부
    부트캠프
  • 최근 댓글

  • 250x250
  • hELLO· Designed By정상우.v4.10.4
pangil_kim
[React] TanStack Query(React Query) 깊게 파고들기 : useQuery와 캐시 생명주기의 모든 것
상단으로

티스토리툴바