Skip to content

TanStack Query 세팅

TanStack Query는 서버 상태(비동기 데이터)를 캐싱하고 동기화하기 위한 라이브러리이다.


왜 TanStack Query를 쓸까?

서버 상태의 어려움

React에서 서버 데이터를 단순히 fetch + useEffect로만 관리하면 다음 문제가 자주 발생한다.

  • 동일한 API를 여러 컴포넌트에서 중복 요청
  • 로딩/에러 처리 코드가 매번 반복됨 (보일러플레이트)
  • 캐시 정책이 없어서 화면 이동할 때마다 재요청
  • 데이터 수정(POST/PUT) 후 목록을 수동으로 다시 불러와야 함
  • 네트워크 복구, 탭 전환 시 데이터 동기화 어려움

이런 문제를 표준화된 방식으로 해결해 주는 것이 TanStack Query다.

TanStack Query를 안 쓰면 무엇을 직접 해야 할까?

아래 기능을 전부 직접 구현해야 한다:

  • 요청 중복 방지
  • 캐시 저장 및 만료 정책 (staleTime, cacheTime)
  • 로딩/에러 상태 표준화
  • 실패 시 재시도 로직
  • 데이터 수정 후 자동 갱신(invalidate)
  • optimistic update(낙관적 업데이트)

가능하지만, 앱이 커질수록 코드가 복잡해지고 유지보수가 급격히 어려워진다.
결국 데이터 fetching 로직이 아니라 상태 관리 문제가 된다.


언제 TanStack Query를 도입하면 좋을까?

다음과 같은 경우 도입을 권장한다:

  • API 호출이 많고 화면 간 데이터 공유가 필요한 경우
  • 동일 데이터를 여러 화면에서 사용하는 경우
  • 로딩/에러 처리 패턴을 표준화하고 싶은 경우
  • 데이터 수정 후 목록 갱신이 잦은 경우
  • 성능 최적화(캐시 활용)가 필요한 경우

설치

bash
# 서버 상태 관리 라이브러리
npm i @tanstack/react-query

# React Query 상태를 시각적으로 확인하기 위한 개발용 도구
npm install -D @tanstack/react-query-devtools

# TanStack Query 사용 시 실수를 방지하기 위한 ESLint 플러그인
npm i -D @tanstack/eslint-plugin-query

기본 설정

실제 프로젝트에서는 유지보수를 위해 QueryClient를 별도 파일로 분리하는 것을 권장한다.

1. QueryClient 분리

ts
// src/lib/queryClient.ts
import { QueryClient } from '@tanstack/react-query';

export const queryClient = new QueryClient({
  defaultOptions: {
    queries: {
      retry: 1, // 네트워크 오류 발생 시 1회만 재시도
      refetchOnWindowFocus: false, // 브라우저 포커스 시 자동 재요청 방지
    },
  },
});

2. Provider 전역 적용

tsx
// src/main.tsx
import React from 'react';
import ReactDOM from 'react-dom/client';
import { QueryClientProvider } from '@tanstack/react-query';
import { ReactQueryDevtools } from '@tanstack/react-query-devtools';
import App from './App';
import { queryClient } from './lib/queryClient';

ReactDOM.createRoot(document.getElementById('root')!).render(
  <React.StrictMode>
    <QueryClientProvider client={queryClient}>
      <App />
      {/* 개발 환경에서만 Devtools 렌더링 */}
      {import.meta.env.DEV && <ReactQueryDevtools initialIsOpen={false} />}
    </QueryClientProvider>
  </React.StrictMode>
);

이후 모든 서버 데이터는 useQuery, useMutation 훅을 통해 관리한다.


3. ESLint 설정

.eslintrc.cjs 또는 .eslintrc.json에 TanStack Query 플러그인을 추가한다.

javascript
module.exports = {
  extends: [
    // ... 기존 설정
    'plugin:@tanstack/eslint-plugin-query/recommended',
  ],
  plugins: [
    // ... 기존 플러그인
    '@tanstack/query',
  ],
  rules: {
    '@tanstack/query/exhaustive-deps': 'error',
    '@tanstack/query/no-unstable-deps': 'error',
  },
};

ESLint 규칙의 의미

  • exhaustive-deps: 쿼리 키와 의존성이 누락되지 않도록 보장
  • no-unstable-deps: 불안정한 객체를 쿼리 키로 쓰는 것을 방지

주요 설정 옵션 설명

Query 기본 옵션

옵션기본값설정값설명
retry31요청 실패 시 재시도 횟수
refetchOnWindowFocustruefalse탭 전환 시 자동 재요청 여부

왜 이렇게 설정했나?

  • retry: 1: 네트워크 오류 발생 시 과도한 재시도를 방지하여 서버 부하를 줄인다.

  • refetchOnWindowFocus: false:

    • 탭 전환할 때마다 자동으로 API를 다시 호출하는 기본 동작 비활성화
    • 예기치 않은 네트워크 요청과 화면 깜빡임 방지
  • 참고: 실시간성이 중요한 서비스(주식, 채팅, 대시보드 등)는 true 유지 권장


Devtools (개발 도구)

React Query Devtools는 개발 환경에서만 동작하며, 다음을 실시간으로 확인할 수 있다:

  • 현재 활성화된 쿼리 목록 및 상태
  • 쿼리 상태: fresh (신선), fetching (요청중), stale (만료됨), inactive (비활성)
  • 캐시에 저장된 데이터 내용
  • 쿼리 무효화(invalidate) 및 수동 리페칭 테스트

사용법

  • 앱 실행 후 화면 하단의 TanStack Query 아이콘을 클릭한다.

장단점

장점

  • 서버 상태 관리 표준화
  • 중복 요청 감소 → 성능 개선
  • 로딩/에러 처리 일관성
  • Devtools로 디버깅 용이
  • Optimistic UI 구현 가능

단점

  • 초기 학습 비용이 있음 (staleTime, cacheTime, queryKey 개념)
  • queryKey 설계가 중요함
  • 단순한 앱에는 과할 수 있음

언제 안 써도 될까?

  • API 호출이 1~2개뿐인 단순 앱
  • 정적 데이터 중심 프로젝트 (블로그, 랜딩 페이지)
  • 서버 상태보다 로컬 UI 상태가 대부분인 경우 (드로잉 앱, 계산기 등)