
최근 팀의 레포지토리를 살펴보다가 package.json에 @tanstack/react-query라는 의존성이 설치된 것을 발견했다. 이게 무슨 라이브러리지? 하는 궁금증에 간단히 사용해보았는데, 사용법은 굉장히 간단하면서도 매우 유용하게 활용할 수 있는 라이브러리라는 생각이 들었다. 그래서 이번 글에서는 React Query, 즉 TanStack Query에 대해 정리해보려고 한다. (+ 과제)
React Query는 원래 이 이름으로 시작했지만, v4부터 Vue나 Svelte 등 다른 프레임워크에서도 활용할 수 있도록 기능이 확장되면서 TanStack Query라는 이름으로 변경되었다. (하지만 이 글에서는 React Query라는 이름에 더 익숙한 사람이 많을 것이라고 생각하여, React Query로 표기하겠다.)
React Query는 서버 상태를 페칭(fetching), 캐싱(caching), 동기화(synchronization), 업데이트(updating)하는 작업을 쉽게 처리할 수 있도록 도와주는 라이브러리이다.
페칭(fetching): 웹 애플리케이션에서 서버로부터 데이터를 요청하고 가져오는 과정.
캐싱(caching): 자주 사용되는 데이터나 값을 임시로 저장하여, 동일한 요청 시 서버에 다시 요청하지 않고 빠르게 불러오는 방식.
동기화(synchronization): 클라이언트의 데이터 상태와 서버의 데이터 상태를 일치시키는 과정.
업데이트(updating): 기존 데이터를 수정하거나 새로운 데이터로 교체하는 과정.
React Query는 다음과 같은 상황에서 특히 유용하다.
서버 상태 관리가 필요한 경우: useState, useEffect로 관리하기 어려운 서버 데이터를 보다 효율적으로 관리할 수 있다.
자주 갱신되는 데이터를 자동으로 동기화해야 할 때: 실시간 피드, 대시보드, 알림 기능 등을 쉽게 구현할 수 있다.
캐싱을 활용해 불필요한 요청을 줄이고 싶을 때: 같은 데이터를 여러 곳에서 사용할 때 동일한 요청을 최소화할 수 있다.
로딩 및 에러 상태 관리를 간편하게 하고 싶을 때: isLoading, isError 등의 내장 상태를 활용하면 로딩과 에러 상태를 손쉽게 처리할 수 있다.
QueryClient는 모든 query와 mutation에 대한 상태와 캐시를 관리하는 객체이다.
const queryClient = new QueryClient();
QueryClientProvider는 하위 컴포넌트들이 QueryClient에 접근할 수 있도록 도와주는 컴포넌트이다.
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
const queryClient = new QueryClient();
createRoot(document.getElementById("root")!).render(
<QueryClientProvider client={queryClient}>
<App />
</QueryClientProvider>
);
QueryClientProvider는 client라는 prop을 받으며, 이 client에는 QueryClient의 인스턴스를 전달해야 한다. QueryClientProvider로 앱을 감싸면 하위 컴포넌트들에서 QueryClient를 통해 query와 mutation을 사용할 수 있게 된다.
useQuery는 React Query에서 가장 기본적인 쿼리 훅으로, 컴포넌트에서 서버로부터 데이터를 가져올 때 사용되며 객체를 인자로 받는다.
쿼리란 데이터베이스나 서버에서 원하는 정보를 검색하거나 요청하는 것을 의미한다.
const 반환값 = useQuery(옵션);
useQuery의 반환값에는 보통 다음과 같은 상태 값과 함수가 포함된다.
data: 쿼리로 가져온 데이터isLoading: 데이터가 로드 중인지 여부error: 데이터 요청 중 발생한 에러refetch: 수동으로 데이터를 다시 가져오는 함수useQuery에서 자주 사용되는 옵션은 아래와 같다.
| 옵션 | 설명 | 기본값 |
|---|---|---|
queryKey | 쿼리를 고유하게 식별하는 키(식별자) | (필수) |
queryFn | 데이터를 가져오는 함수 (API 호출 등) | (필수) |
enabled | 쿼리 자동 실행 여부. false로 설정하면 수동으로 실행 가능 | true |
staleTime | 데이터가 신선한 상태로 유지되는 시간(ms). | 0 |
gcTime | 쿼리 데이터가 캐시에 유지되는 시간(ms). | 300000 (5분) |
refetchOnWindowFocus | 브라우저 창에 다시 포커스될 때 자동으로 데이터 갱신 여부 | true |
retry | 쿼리 실패 시 자동 재시도 횟수 | 3 |
select | 가져온 데이터를 변형하거나 가공하는 함수 | 없음 |
initialData | 쿼리가 생성되거나 캐시되기 전에 사용할 초기 데이터 | 없음 |
useMutation은 React Query에서 데이터 변경 작업(생성, 수정, 삭제 등)을 처리하기 위한 훅이다. 이를 사용하면 데이터 변경 요청을 쉽게 관리할 수 있으며, 요청의 성공, 실패, 로딩 상태 등을 편리하게 추적할 수 있다.
const 반환값 = useMutation(옵션);
useMutation의 반환값에는 보통 다음과 같은 상태 값과 함수가 포함된다.
mutate: 변이 요청을 실행하는 함수data: 변이가 성공했을 때 반환된 데이터isLoading: 변이 요청이 진행 중인지 여부error: 변이 요청 중 발생한 에러useMutation에서 자주 사용되는 옵션은 아래와 같다.
| 옵션 | 설명 | 기본값 |
|---|---|---|
mutationFn | 실행할 비동기 변이 함수 | (필수) |
onSuccess | 변이가 성공했을 때 호출되는 함수 | 없음 |
onError | 변이 중 오류가 발생했을 때 호출되는 함수 | 없음 |
onSettled | 변이가 성공하거나 실패해도 항상 호출되는 함수 | 없음 |
onMutate | 변이 함수가 실행되기 전에 호출되는 함수 | 없음 |
retry | 변이 실패 시 재시도 횟수 | 0 |
retryDelay | 재시도 시 딜레이 시간(ms) | 자동 설정 |
npm i @tanstack/react-query
yarn add @tanstack/react-query
pnpm add @tanstack/react-query
import axios from "axios";
import { useQuery } from "@tanstack/react-query";
const App = () => {
const { data, isLoading, error } = useQuery({
queryKey: ["userData"],
queryFn: () => axios.get("/api/user").then((res) => res.data),
staleTime: 10000, // 10초 동안 데이터 신선하게 유지
gcTime: 300000, // 5분 동안 캐시 유지
refetchOnWindowFocus: false, // 창 포커스 시 자동 갱신 비활성화
});
if (isLoading) return <div>로딩 중...</div>;
if (error) return <div>에러 발생: {error.message}</div>;
return (
<div>
<h1>사용자 정보</h1>
<p>이름: {data.name}</p>
<p>이메일: {data.email}</p>
</div>
);
};
export default App;
모든 코드를 완벽히 이해한 것은 아니지만, 나는 Hello, GSM이 React Query를 활용한 이유가 최신 데이터를 쉽게 유지하고 사용자의 정보를 편리하게 불러오기 위해서라고 생각한다.
Hello, GSM은 입학 지원 시스템인 만큼 사용자의 정보와 합격 여부가 가장 중요한 데이터일 것이다. React Query를 사용하면 데이터를 가져오고 수정하는 과정이 더욱 간편해지므로, 이러한 이유로 React Query를 도입한 것 같다.
Hello, GSM 코드에서 React Query가 사용된 모든 부분을 찾아보지는 못했지만, 내가 확인한 코드들은 대부분 사용자 정보와 입학 원서와 관련된 기능이었다.
사용자 정보와 관련된 코드는 회원가입 시 전화번호 중복 체크, 회원 정보 조회, 1차 합격 결과, 2차 합격 결과 등을 useQuery를 활용하여 가져오고 관리하고 있었다.
입학 원서와 관련된 코드는 현재 로그인한 사용자의 원서 조회, 원서 제출, 이미지 업로드, 그리고 확실하진 않지만 졸업 유형에 따른 성적 조회 등의 기능을 useQuery와 useMutation을 활용하여 관리하고 있었다.
staleTime은 데이터가 "신선(fresh)"한 상태로 유지되는 시간을 설정하는 옵션이다. 데이터가 stale 상태로 변경되기 전까지, 즉 데이터가 "변경이 필요 없는 상태"로 간주되는 시간을 의미한다. 이 시간이 지나면, React Query는 데이터를 재요청한다.
gcTime은 데이터가 stale 상태로 바뀐 이후, 캐시가 얼마나 오래 유지될지 설정하는 옵션이다. 즉, 데이터가 stale 상태로 변경된 후, 캐시가 제거되기까지의 시간을 설정한다. gcTime이 지나면, 해당 데이터는 garbage collection에 의해 삭제된다.
staleTime: 데이터가 fresh 상태로 유지되는 시간gcTime: 데이터가 stale 상태로 변경된 후, 캐시가 얼마나 오래 유지될지 설정하는 시간오늘은 React Query에 대해 알아보았다. 개인적으로 매우 유용하고 사용법도 간단하다고 느꼈다. 기본적인 기능은 쉽게 다룰 수 있을 것 같지만, 아직 많이 사용해보지 않아서 앞으로 기회가 생길 때 유용하게 활용해봐야겠다.