React 앱을 만들다 보면 서버에서 데이터를 가져오고, 갱신하고, 에러를 처리하는 과정이 필연적으로 따라온다. 이 과정은 단순히 fetch를 호출하는 문제를 넘어, 로딩 상태 관리, 에러 핸들링, 데이터 캐싱, 자동 갱신(refetch) 등 수많은 고려 사항을 동반한다. 이런 복잡한 흐름 속에서 등장한 것이 바로 TanStack React Query다.
1. 서버 상태란 무엇인가
먼저 구분해야 할 개념이 있다. 바로 클라이언트 상태(client state)와 서버 상태(server state)다.
•
클라이언트 상태는 사용자의 인터랙션에 의해 즉시 변경되는 데이터다. 예를 들어, 모달 열림 여부, 입력 폼의 값 등이 이에 해당한다.
•
서버 상태는 API 호출을 통해 받아오는 데이터로, 클라이언트가 직접 수정할 수 없다. 비동기 요청을 통해서만 읽거나 변경할 수 있다.
이 서버 상태를 단순한 useState로 관리하려고 하면 문제가 시작된다.
로딩, 에러, 데이터 갱신 타이밍 등 모든 것을 직접 제어해야 하고, 네트워크 요청이 중복되거나 최신 데이터가 보장되지 않는 등 비효율적인 구조가 쉽게 만들어진다.
2. React Query가 해결하는 문제
캐싱과 동기화
React Query의 가장 강력한 기능은 데이터 캐싱이다.
동일한 요청에 대해 이미 캐싱된 데이터가 있다면, 네트워크 요청 없이 즉시 캐시를 반환한다. 동시에, 백그라운드에서 새로운 데이터를 가져와 자동으로 최신 상태를 유지한다.
const { data, isLoading } = useQuery({
queryKey: ["user", userId],
queryFn: () => fetchUser(userId),
staleTime: 1000 * 60 * 5, // 5분 동안 캐시 유지
});
TypeScript
복사
이 단 한 줄의 옵션(staleTime)으로 “데이터를 언제까지 신선하다고 판단할지”를 선언적으로 관리할 수 있다.
로딩과 에러 상태의 자동 관리
React Query는 API 호출의 전형적인 3단계 — 로딩, 성공, 실패 — 를 기본적으로 다뤄준다.
별도의 useState를 만들어 isLoading, isError를 관리할 필요가 없다.
const { data, isLoading, isError } = useQuery({
queryKey: ["posts"],
queryFn: fetchPosts,
});
TypeScript
복사
로딩 상태일 땐 스피너를, 에러일 땐 안내 메시지를 띄우는 것이 한결 간단해진다.
즉, “데이터 요청”보다 “데이터로 무엇을 보여줄지”에 집중할 수 있게 된다.
데이터 무효화와 리프레시
React Query는 서버 데이터의 변경을 “무효화(invalidate)”라는 개념으로 다룬다.
예를 들어, 게시글 작성이 성공하면 ["posts"] 캐시를 무효화해 목록이 자동으로 최신 상태로 갱신된다.
const queryClient = useQueryClient();
const mutation = useMutation({
mutationFn: createPost,
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: ["posts"] });
},
});
TypeScript
복사
덕분에, 데이터 일관성을 유지하기 위한 추가적인 관리 코드가 사라진다.
3. React Query를 사용하지 않는다면
React Query 없이 동일한 기능을 구현하려면 다음과 같은 작업을 모두 직접 처리해야 한다.
•
요청 중 상태 관리 (loading, error, data)
•
중복 요청 방지 로직
•
데이터 캐싱 및 만료 처리
•
실패 시 재시도 로직
•
백그라운드 리패칭
이 모든 것을 수동으로 작성하면 코드가 기하급수적으로 복잡해진다.
React Query는 이 로직들을 표준화된 패턴으로 추상화하여, 개발자가 “언제 데이터를 다시 불러와야 하는가?” 같은 고민에서 벗어나게 해준다.
4. React Query의 한계
물론 완벽한 도구는 없다. React Query에도 단점은 존재한다.
•
캐싱 전략 관리의 복잡성: staleTime, gcTime, refetchOnWindowFocus 등의 설정을 잘못하면, 최신 데이터가 보장되지 않거나 불필요한 요청이 발생한다.
•
초기 학습 곡선: Query Key 설계, 데이터 무효화 전략 등 개념을 이해해야 한다.
•
클라이언트 상태와의 결합 한계: 서버 상태와 사용자 입력(클라이언트 상태)이 복잡하게 얽혀 있는 경우, 별도의 전역 상태 관리(Zustand, Redux 등)와 병행해야 한다.
_(1).jpeg&blockId=0e552736-74f0-4f5a-89e1-328d4931ca7c)