React

TanStack Query 시작하기 , Tanstack Query를 사용하는 이유를 설명해 주세요

Chrysans 2025. 4. 21. 12:07
728x90
반응형

TanStack Query 시작하기 , Tanstack Query를 사용하는 이유를 설명해 주세요

react query(리액트쿼리) 로고와 타이틀

 

왜 TanStack Query를 사용해야 하는지?

 

프론트엔드 개발에서 서버 데이터와의 동기화, 캐싱, 에러 처리, 로딩 상태 관리… 이 모든 것을 직접 구현하려다 보면 코드가 복잡해지고, 버그도 늘어나기 쉽습니다.

이럴때 필요한 것이 바로 TanStack Queryt(구 React Query) 입니다.

클라인언트 상태, 서버 상태 , 데이터 패칭, 캐싱, 동기화 , 리트라이 , 뮤테이션까지 한번에 해결가능한 tanStack Query 에 대해서 알아보도록 하겠습니다. 


목차

  1. TanStack Query란?
  2. TanStack Query가 필요한 이유: 전통적 상태 관리와의 비교
  3. 실전 예제로 배우는 TanStack Query
  4. 주요 기능 및 옵션 설명
  5. 트러블슈팅 & 실전 팁
  6. 베스트 프랙티스 vs. 안티패턴
  7. 용어 설명

1. TanStack Query란?

TanStack Query는 서버 상태(server state) 관리에 특화된 데이터 페칭 라이브러리입니다.
React, Vue, Svelte 등 다양한 프레임워크에서 사용 가능하며,
특히 비동기 데이터 요청캐싱, 동기화, 자동 재요청 등 서버 데이터 관리의 복잡성을 획기적으로 줄여줍니다.

서버 상태

  • DB나 외부 API 등 서버에서 관리하는 데이터
  • 여러 사용자가 공유하는 데이터
  • 예시: 사용자 프로필 정보, 게시글 데이터, 상품 정보, 결제 내역 등

클라이언트 상태

  • UI의 토글 상태, 입력값 등 프론트엔드에서만 의미 있는 데이터
  • 특정 사용자의 브라우저/기기에만 존재하는 로컬 데이터
  • 예시: 모달 창 열림/닫힘 상태, 폼 입력값, 테마 설정, 페이지 스크롤 위치 등

2. TanStack Query가 필요한 이유: 전통적 상태 관리와의 비교

기존 방식의 한계

예시: useState + useEffect로 데이터 요청

const [data, setData] = useState(null); 
const [loading, setLoading] = useState(true); 
const [error, setError] = useState(null); 

useEffect(() => { 
	fetch('/api/posts') 
	.then(res => res.json()) .then(setData) 
	.catch(setError) 
	.finally(() => setLoading(false)); 
 }, []);
 문제점
  • 로딩/에러 상태 직접 관리 → 코드 중복
  • 같은 데이터 여러 컴포넌트에서 요청 시 중복 네트워크 발생
  • 데이터 갱신(동기화) 로직 직접 구현 필요
  • 캐싱, 백그라운드 업데이트, 자동 재시도 등 고급 기능 직접 구현해야 함

TanStack Query 도입 시

import { useQuery } from '@tanstack/react-query'; 
const { data, isLoading, isError, error } = useQuery({
	queryKey: ['posts'], 
	queryFn: () => fetch('/api/posts').then(res => res.json()),
});

장점

  • 로딩/에러/성공 상태 자동 관리
  • 캐싱 및 중복 요청 방지
  • 데이터 신선도(staleTime), 자동 재요청 등 고급 옵션 지원
  • 코드가 간결해지고, 유지보수가 쉬워짐

Redux 등 전역 상태 관리와의 차이 

  TanStack   QueryRedux/Context 
목적 서버 상태(비동기 데이터) 관리 클라이언트 상태(동기 데이터) 관리
코드량 적음 많음(보일러플레이트)
비동기 지원 내장 (자동 상태관리) 미들웨어 필요 (redux-thunk 등)
캐싱/동기화 내장 직접 구현 필요
SSR 지원 매우 우수 직접 구현 필요

3. 실전 예제로 배우는 TanStack Query

3.1 기본 데이터 요청 

import { useQuery } from '@tanstack/react-query';

function PostList() {
  const { data, isLoading, isError, error } = useQuery({
    queryKey: ['posts'],
    queryFn: async () => {
      const res = await fetch('/api/posts');
      if (!res.ok) throw new Error('데이터 요청 실패');
      return res.json();
    },
    staleTime: 60 * 1000, // 1분간 데이터 신선하게 유지
    retry: 2,             // 실패 시 2번까지 재시도
  });

  if (isLoading) return <div>로딩 중...</div>;
  if (isError) return <div>에러: {error.message}</div>;

  return (
    <ul>
      {data.map(post => (
        <li key={post.id}>{post.title}</li>
      ))}
    </ul>
  );
}
  • useQuery는 데이터 요청, 캐싱, 상태 관리까지 한 번에!
  • queryKey는 캐시의 고유 식별자(동일 키면 중복 요청 방지)
  • staleTime으로 데이터 신선도 제어
  • retry로 네트워크 이슈에 유연하게 대응

3.2 데이터 생성/수정/삭제 (Mutation)

import { useMutation, useQueryClient } from '@tanstack/react-query';

function CreatePost() {
  const queryClient = useQueryClient();
  const mutation = useMutation({
    mutationFn: (newPost) =>
      fetch('/api/posts', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify(newPost),
      }).then(res => res.json()),
    onSuccess: () => {
      // 성공 시 posts 쿼리 무효화(자동 재요청)
      queryClient.invalidateQueries({ queryKey: ['posts'] });
    },
  });

  // ...
}
  • useMutation은 서버 데이터 변경(POST/PUT/DELETE)에 사용
  • onSuccess에서 관련 쿼리 무효화로 데이터 일관성 유지

3.3 페이지네이션/무한 스크롤

import { useInfiniteQuery } from '@tanstack/react-query';

function InfinitePosts() {
  const {
    data,
    fetchNextPage,
    hasNextPage,
    isFetchingNextPage,
  } = useInfiniteQuery({
    queryKey: ['posts'],
    queryFn: ({ pageParam = 1 }) =>
      fetch(`/api/posts?page=${pageParam}`).then(res => res.json()),
    getNextPageParam: (lastPage, allPages) =>
      lastPage.hasNext ? allPages.length + 1 : undefined,
  });

  // ... 스크롤 감지 후 fetchNextPage 호출
}
  • useInfiniteQuery는 무한 스크롤, 페이지네이션에 최적화
  • getNextPageParam으로 다음 페이지 조건 제어

4. 주요 기능 및 옵션 설명

핵심 옵션 한눈에 보기 

옵션명 설명 예시값
queryKey 쿼리 식별자 (배열 권장) ['posts', page]
queryFn 데이터를 불러오는 함수 () => fetch('/api/posts')
staleTime 데이터 신선도 유지 시간(ms) 60 * 1000 (1분)
cacheTime 메모리 캐시 유지 시간(ms) 5 * 60 * 1000 (5분)
refetchOnWindowFocus 윈도우 포커스 시 자동 재요청 여부 true/false
enabled 조건부 쿼리 활성화 !!userId
retry 실패 시 재시도 횟수 2, 3, (error) => ...
onSuccess 성공 시 콜백 (data) => ...
onError 에러 시 콜백 (error) => ...

5. 트러블슈팅 & 실전 팁

쿼리 키 관리가 꼬일 때

  • 항상 배열 형태로, 계층적으로 관리
  • 예시: ['users', userId, 'posts']

데이터가 자동으로 갱신되지 않을 때

  • mutation 후 invalidateQueries로 쿼리 무효화
  • enabled 옵션 활용: userId 등 필수 값이 없을 때 쿼리 비활성화

불필요한 네트워크 요청 방지

  • staleTime, cacheTime을 상황에 맞게 조절
  • 자주 변하지 않는 데이터는 staleTime을 길게

에러 핸들링

  • onError 콜백에서 toast 등 사용자 알림 처리
  • 글로벌 에러 핸들링은 QueryClient의 queryCache 옵션 활용

6. 베스트 프랙티스 vs. 안티패턴

데이터 페칭 및 캐싱

베스트 프랙티스 안티패턴/주의점
일관된 queryKey 구조 사용하기 ([entity, id] 형태 권장) 복잡하거나 일관성 없는 queryKey 구조 사용
관심사 분리를 위해 커스텀 훅으로 쿼리 로직 캡슐화 컴포넌트 내에 직접 복잡한 쿼리 로직 작성
타입 안전성을 위해 TypeScript 사용 타입 정의 없이 사용하여 런타임 에러 위험 증가
필요한 경우에만 enabled 옵션 사용 조건부 로직을 위해 컴포넌트 렌더링 조건 사용
전역 설정을 위해 QueryClient 기본값 구성 모든 쿼리마다 반복적인 옵션 설정

상태 관리

베스트 프랙티스   안티패턴/주의점
isLoading과 isFetching 상태 구분해서 사용 두 상태를 혼동하여 잘못된 로딩 UI 표시
에러 처리를 위해 isError와 error 활용 queryFn 내부에서 에러를 무시하거나 숨기기
select 옵션으로 필요한 데이터만 변환/추출 불필요한 리렌더링을 유발하는 컴포넌트 내 데이터 변환
참조 안정성을 위해 useCallback으로 queryFn 감싸기(fn by fn) 렌더링마다 새로운 함수 참조 생성 (fn by fn)
초기 데이터를 위해 initialData 또는 placeholderData 활용 로딩 상태 처리를 위한 복잡한 조건부 렌더링

뮤테이션 및 데이터 업데이트

베스트 프랙티스 안티패턴/주의점
낙관적 업데이트를 위해 onMutate와 context 활용 뮤테이션 후 수동으로 쿼리 리페칭만 의존
관련 쿼리 무효화를 위해 invalidateQueries 사용 단일 쿼리만 무효화하여 관련 데이터 불일치 발생
쿼리 데이터 직접 수정을 위해 setQueryData 활용 서버 상태와 클라이언트 상태 불일치 방치
에러 발생 시 이전 상태로 복원하기 위해 onError 활용 낙관적 업데이트 후 에러 처리 누락
뮤테이션 성공 후 적절한 사용자 피드백 제공 뮤테이션 상태 변화를 사용자에게 알리지 않음

네트워크 및 성능 최적화

베스트 프랙티스 안티패턴/주의점
적절한 staleTime 설정으로 불필요한 리패칭 방지 모든 쿼리에 기본 staleTime: 0 사용
데이터 사용 패턴에 따라 cacheTime 조정 너무 짧은 cacheTime으로 캐시 이점 감소
네트워크 상태에 따른 재시도 전략 구성 무한 재시도 설정 또는 재시도 없음
필요한 경우에만 refetchOnReconnect 활용 모든 쿼리에 불필요한 리커넥트 리패칭 활성화
인증 토큰 관리를 위한 QueryClient 기본 설정 활용 각 쿼리마다 인증 로직 중복 구현

7. 용어 설명

  • 서버 상태(Server State): 서버에서 관리되고 여러 사용자가 공유하는 데이터
  • 클라이언트 상태(Client State): UI 토글, 입력값 등 프론트엔드에서만 의미 있는 상태
  • 쿼리 키(Query Key): 쿼리의 고유 식별자, 캐싱 및 중복 요청 방지에 사용
  • 캐싱(Caching): 이미 불러온 데이터를 메모리에 저장해 재사용
  • 낙관적 업데이트(Optimistic Update): 서버 응답 전 UI를 먼저 변경, 실패 시 롤백
  • SSR(Server Side Rendering): 서버에서 HTML을 미리 렌더링해 SEO 및 초기 속도 개선

 
 

https://tanstack.com/query/latest

 

TanStack Query

Powerful asynchronous state management, server-state utilities and data fetching. Fetch, cache, update, and wrangle all forms of async data in your TS/JS, React, Vue, Solid, Svelte & Angular applications all without touching any "global state"

tanstack.com

 

728x90
반응형