저번에 react-query 개념적인 부분에 대해서 포스팅해보았다.
react-query에 대해서 좀 더 공부해보니 TanStack-Query 라는 이름으로 변경되었더라.
이제 react 뿐만 아니라 vue나 angular에서도 쓸 수 있도록 업데이트를 한 것 같다. 그래서 이름을 TanStack-Query 으로 변경한 이유.
아무튼 tanstack-query 라이브러리에 대해 좀 더 디테일하게 알아보자!
🎯 개요
Tanstack Query(React-query)은 React 애플리케이션에서 서버 상태(Server State) 관리를 쉽게 해주는 라이브러리이다.
- 주요 기능 : 데이터 패칭(Fetching), 캐싱(Caching), 동기화(Synchronization), 업데이트 및 에러 처리를 선언적이고 효율적으로 처리. 복잡한 비동기 로직을 간소화 → 애플리케이션 성능 향상
🔧 기술 상세정보
useQuery 훅
- useQuery 훅은 주로 서버로부터 데이터를 가져오는 작업에 사용
사용 및 목적
- GET 요청과 같이 읽기 작업을 수행하고 그 결과를 캐싱 및 관리
- 데이터가 오래되었는지(stale) 여부를 판단하여 자동으로 데이터를 다시 가져오도록(refetch) 관리
즉, useQuery 훅은 서버로부터 데이터를 가져와야 하는 상황(GET)에서 쓰인다.
주요 옵션
- queryKey : 쿼리의 고유 식별자이며, 캐싱 및 리패칭의 기준이 된다. 배열 형태로 지정 (필수)
- queryFn : 실제로 데이터를 가져오는 비동기 함수. (Promise를 반환해야 함)
- 서비스단에서 작성한 API 호출 함수를 여기에 지정.
- staleTime : 데이터가 ‘fresh’ 상태로 유지되는 시간 (이 시간 동안은 리패칭하지 않음)
- enabled : false로 설정 시 쿼리가 자동으로 실행되지 않도록 설정.
- ex. enabled: !!id, // id가 있을 때만 쿼리 실행
- retry : API 요청 실패 시 재시도 설정
- ex. retry: 1 // 실패 시 1번 재시도
예시
import { useQuery } from '@tanstack/react-query'
// TanStack Query로 게시글 데이터 조회
const {
data: postData,
isLoading,
isError,
error,
} = useQuery({
queryKey: ['post', id], // 캐시 키
queryFn: () => fetchPost(id), // 데이터 페칭 함수
enabled: !!id, // id가 있을 때만 쿼리 실행
staleTime: 5 * 60 * 1000, // 5분 동안 데이터를 fresh로 간주
retry: 1, // 실패 시 1번 재시도
});
Fresh(신선한) 상태
Fresh 상태는 데이터가 최근에 가져와졌으며 현재 유효하다고 간주되는 상태
- 정의 : 데이터가 staleTime 옵션에 설정된 시간(기본값 0)이 지나지 않은 상태
- 특징 :
- 데이터가 캐시에서 즉시 사용되며, 새로운 API 요청(refetching)을 자동으로 트리거하지 않는다.
- 앱이 마운트되거나, 윈도우 포커스가 돌아오거나, 네트워크 재연결이 발생해도 리패칭이 일어나지 않습니다.
staleTime의 역할
- staleTime은 데이터가 Fresh 상태로 유지되는 시간을 ms단위로 정의
- 기본값 : statleTime: 0
- 데이터를 가져오자마자 즉시 stale 상태
- 이 경우, 컴포넌트 마운트, 윈도우 포커스 등의 이벤트가 발생하면 백그라운드에서 리패칭을 시도
- 예시 : staleTime: 1000 * 60 * 5 (5분)
- 데이터를 가져온 후 5분 동안은 Fresh 상태로 유지되어, 해당 쿼리를 사용하는 모든 컴포넌트는 캐시된 데이터를 즉시 사용
Stale(오래된) 상태
데이터가 staleTime 옵션에 설정된 시간을 초과하여 더 이상 유효하지 않을 수 있다고 간주되는 상태
- 정의 : 데이터가 캐시에 있지만, 업데이트가 필요할 수 있음을 나타냄
- 특징:
- 데이터는 캐시에서 즉시 반환되어 화면에 표시되지만, 동시에 자동으로 백그라운드 리패칭을 시도하는 조건이 된다.
- 특정 이벤트가 발생하면 Stale 상태의 데이터를 자동으로 업데이트(리패칭)한다.
Stale 상태일 때 자동 리패칭 조건
데이터가 Stale 상태인 경우, 다음 이벤트 중 하나가 발생하면 Tanstack Query는 백그라운드에서 리패칭을 수행.
- 새로운 쿼리 인스턴스가 마운트될 때,
- 윈도우에 다시 포커스가 돌아올 때 (브라우저 탭을 전환했다 돌아올 때 등)
- 네트워크가 재연결될 때
- 특정 시간 간격으로 리패칭 인터벌이 설정되어 있을 떄
- 리패칭 인터벌 : 일정한 시간 간격마다 서버로부터 Refetching
📄 데이터 패칭(useQuery) 관련 요약 정리
Tanstack Query는 서버 상태와 클라이언트 상태를 명확히 분리하여 관리한다.
여기서 쓰이는 개념이 Fresh와 Stale 이다.
Fresh는 데이터를 최근에 가져와 데이터가 유효한 상태를 말한다.
반대로 Stale은 데이터가 유효하지 않을 가능성이 있어 업데이트가 필요할 수 있다고 간주한 상태이다.
그래서 staleTime을 기준으로 Fresh상태인지 Stale 상태인지를 구분한다.
데이터가 stale 상태이면, 특정 이벤트(컴포넌트 재마운트, 윈도우 재포커싱, 네트워크 재연결 등)이 발생했을 때, 백그라운드에서 refetching이 이루어지고 성공적으로 완료가 되면 캐시(TanStack Query 내부캐시)가 업데이트가 되면서 UI가 리렌더링된다.
useMutation 훅
useMutation 훅은 주로 서버의 데이터를 변경하는 작업에 사용
사용 및 목적
- POST, PUT, DELETE 요청과 같이 서버 상태를 변경하는 작업을 수행할 때 사용
- mutate 함수를 호출하여 API 요청을 직접 트리거해야 한다.
주요 옵션
- mutationFn : 서버에 데이터를 변경하는 비동기 함수
- 서비스단에서 작성한 API 호출 함수를 여기에 지정.
- onMutate : mutationFn이 실행되기 전에 먼저 실행. 낙관적 업데이트 시 사용
- 여기서 반환된 값을 onError, onSettled에 전달됨
- 낙관적 업데이트 : 업데이트가 잘 되었다고 판단하여 데이터가 변경되었을 때 서버로부터 오는 응답을 기다리지 않고, UI를 즉시 업데이트하는 방식 (다만, 오류가 발생했을 때 이를 적절히 처리하고 원상 복구 시키는 로직을 잘 작성해야 한다.) ex. 좋아요 수
- isPending : 뮤테이션이 현재 진행 중인지 여부 (isLoading과 동일한 역할)
- onSuccess : 뮤테이션이 성공했을 때 실행
- onError : 뮤테이션이 실패했을 때 실행
- onSettled : 뮤테이션 성공 여부와 상관없이 완료되었을 때 실행
- try catch에서 finally와 동일
즉, useMutation 훅은 폼 제출, 아이템 삭제 등 사용자 상호작용에 의해 API 요청이 발생할 때 사용이 된다.
요청, 성공, 에러(실패) 상태를 괸라하고, onMutate, onSuccess, onError 등 이러한 함수를 통해 요청 전, 요청 후 로직을 설계할 수 있다.
예시: 게시글 업데이트 (post)
// TanStack Query Mutation
// useMutation : 데이터 변경(생성/수정/삭제) 작업을 위한 훅.
const updateMutation = useMutation({
mutationFn: updatePost, // 데이터 업데이트를 위한 API 요청 메소드
onSuccess: () => {
// 성공 시 캐시 업데이트
queryClient.invalidateQueries({ queryKey: ['post', id] }); // 게시물 업데이트
queryClient.invalidateQueries({ queryKey: ['posts'] }); // 목록 캐시도 무효화
alert('게시글이 수정되었습니다.');
// history.push(`/posts/${id}`); // 상세 페이지로 이동
},
onError: (error) => {
console.error('수정 실패:', error);
alert('수정에 실패했습니다.');
},
});
QueryClient (캐시 관리자)
QueryClient는 TanStack Query의 중앙 캐시를 포함하고 관리하는 핵심 객체
React 컴포넌트 외부에서 쿼리 캐시를 직접 조작할 수 있게 해준다.
사용 목적
- 캐시 무효화 : 서버 데이터가 변경된 후, 관련 useQuery의 캐시를 Stale 상태로 만들고 자동 리패칭을 유도
- 캐시 수동 업데이트 : API 요청 없이 캐시 데이터를 직접 읽거나 쓸 수 있다.
- 전역 설정 관리 : 애플리케이션 전체의 쿼리 동작을 설정한다.
- 어떤 컴포넌트에서든 queryClient 인스턴스에 접근하여 캐시를 직접 조작할 수 있다.
QueryClient가 전역에서 캐시를 관리할 수 있는 이유!
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
// TanStack Query 클라이언트 생성
const queryClient = new QueryClient({
defaultOptions: {
queries: {
refetchOnWindowFocus: false, // 윈도우 포커스 시 자동 리페치 비활성화
retry: 1, // 실패 시 1번 재시도
staleTime: 30 * 60 * 1000, // 30분 동안 데이터를 fresh로 간주
},
},
});
const container = document.getElementById('root');
ReactDOM.render(
<StrictMode>
<QueryClientProvider client={queryClient}>
<BrowserRouter>
<App />
</BrowserRouter>
</QueryClientProvider>
</StrictMode>
, container);
main.jsx(또는 index.jsx)에서 <QueryClientProvider> 태그로 <App /> 컴포넌트를 감싸고 있기 때문에, 앱의 모든 하위 컴포넌트들이 useQueryClient() 훅을 통해 동일한 queryClient 인스턴스에 접근할 수 있다. (React Context 기반 원리)
queryClient를 통한 캐시 조작
queryClient 객체는 주로 useQueryClient() 훅을 통해 컴포넌트 내에서 접근할 수 있으며, useMutation의 콜백 함수 내에서 특히 중요하게 사용된다.
invalidateQueries(queryKey)
- 지정된 queryKey를 가진 모든 쿼리 데이터를 즉시 Stale 상태로 만들고, Stale 상태가 된 쿼리는 백그라운드에서 자동으로 리패칭을 시도하여 최신 데이터를 가져온다. 즉, 데이터 동기화를 위해 사용된다.
- 예시 :
- 게시글을 성공적으로 업데이트(useMutation)한 후, post id를 가진 게시글 데이터 조회 쿼리를 무효화(해당 쿼리 데이터를 stale상태로 만듦 → 리패칭 유도)하여 해당 게시글 데이터를 자동으로 새로고침한다.
// useMutation의 onSuccess 콜백 함수 내에서 사용 onSuccess: () => { // 성공 시 캐시 업데이트 queryClient.invalidateQueries({ queryKey: ['post', id] }); queryClient.invalidateQueries({ queryKey: ['posts'] }); // 목록 캐시도 무효화 alert('게시글이 수정되었습니다.'); // history.push(`/posts/${id}`); // 상세 페이지로 이동 }
setQueryData(queryKey, updater)
- 서버 요청 없이, 특정 쿼리의 캐시 데이터를 즉시 원하는 값으로 변경
- 예시:
- 서버에서 변경된 데이터를 반환받았을 때, 목록 쿼리의 캐시를 직접 업데이트하여 추가적인 리패칭 없이 UI를 즉시 업데이트할 때 사용
- 낙관적 업데이트를 구현할 때 사용
📄 데이터 업데이트(useMutation) 관련 요약 정리
Tanstack Query에서 서버의 데이터를 변경을 할 때 useMutation 훅을 사용한다.
muatationFn에 서버에 데이터를 변경하는 비동기 함수를 지정하고 onSuccess, onError 함수에서 요청 성공, 실패 시에 대한 로직을 작성할 수 있다. 그리고 onSettled 콜백 함수에 뮤테이션의 성공, 실패와 상관없이 공통적으로 실행해야 하는 로직을 작성할 수 있다.
onMutate는 뮤테이션이 실행되기 전에 실행이 되는데, 보통 낙관적 업데이트 즉, UI를 즉시 업데이트해야 하는 상황(ex. 좋아요 수)에 사용된다.
QueryClient는 TanStack Query의 쿼리 캐시를 관리하고 직접 조작할 수 있게 해주는 객체이다.
주로 useMutation의 콜백 함수(onSuccess, onError 등) 내에서 사용된다.
우리가 데이터를 업데이트를 시킨 후 queryClient에서 제공하는 invalidateQueries 함수를 통해 특정 쿼리키를 가진 쿼리를 캐시 무효화시켜 해당 쿼리 데이터를 자동 리패칭을 유도시킨다.
그리고 setQueryData 함수를 통해 특히 낙관적 업데이트를 구현하고자 할 때 별도의 서버 요청 없이 직접 쿼리 캐시를 업데이트하여 UI를 즉시 업데이트할 할 수 있다.
'Web > React' 카테고리의 다른 글
| [React] react-hook-form 을 활용해 쉽고 편하게 폼(form) 관리하기 (0) | 2025.10.30 |
|---|---|
| [React] 리액트 쿼리에 대해서 (0) | 2025.10.20 |
| [React] react (vite)project 기본적인 개발 구조 설계 (0) | 2025.09.11 |
| [React] vite project 생성 및 구조 가이드 (0) | 2025.09.10 |
| [React] Hook이 대체 뭐야? (useState, useEffect) (1) | 2025.06.30 |