React Query(TanStack Query) 도입 가이드: 우아한 비동기 상태 관리
프론트엔드 개발에서 가장 골치 아픈 문제 중 하나는 "비동기 데이터 관리"입니다. 로딩 상태(isLoading), 에러 처리(isError), 데이터 캐싱, 중복 요청 방지 등을 직접 구현하다 보면 컴포넌트는 금세 useEffect와 useState로 범벅이 됩니다. Redux 같은 전역 상태 관리 라이브러리에 API 데이터를 넣는 것은 보일러플레이트를 증가시키고, 서버 상태(Server State)와 클라이언트 상태(Client State)의 경계를 모호하게 만듭니다.
이러한 문제의 해결사로 등장한 것이 바로 **TanStack Query (구 React Query)**입니다. 이 라이브러리는 "서버 상태"를 관리하는 데 특화되어 있으며, 개발자가 비즈니스 로직에만 집중할 수 있도록 강력한 추상화를 제공합니다.
1. 서버 상태 vs 클라이언트 상태
가장 먼저 이해해야 할 것은 이 두 가지의 차이입니다.
- 클라이언트 상태: UI의 상태(모달 열림 여부, 다크 모드, 입력값 등). 동기적이며 클라이언트가 온전히 소유합니다.
- 서버 상태: DB에 저장된 데이터. 비동기적이며, 다른 사용자에 의해 언제든 변경될 수 있습니다(Out of date).
React Query는 서버 상태를 관리하기 위해 탄생했습니다.
2. 핵심 개념: staleTime과 gcTime
React Query를 처음 접할 때 가장 헷갈리는 것이 이 두 옵션입니다.
- staleTime (상한 시간): 데이터가 "신선하다(fresh)"고 간주되는 시간입니다. 이 시간이 지나면 데이터는 "상했다(stale)"고 판단되며, 다음 요청 시 백그라운드에서 자동으로 리패치(Refetch)가 일어납니다. 기본값은
0입니다. 즉, 받아오자마자 상한 것으로 간주합니다. - gcTime (가비지 컬렉션 시간): 사용되지 않는 데이터(Unused)가 메모리에 남아있는 시간입니다. 기본값은 5분입니다. 컴포넌트가 언마운트되어도 이 시간 동안은 캐시에 데이터가 남아있어, 다시 마운트될 때 네트워크 요청 없이 즉시 데이터를 보여줄 수 있습니다.
3. 실전 활용 패턴
3.1 useQuery로 데이터 가져오기
const { data, isLoading, isError } = useQuery({
queryKey: ['todos'],
queryFn: fetchTodos,
staleTime: 1000 * 60, // 1분간은 신선함 유지
});
단 한 줄로 로딩, 에러, 데이터 상태를 모두 관리할 수 있습니다. 동일한 queryKey를 사용하는 컴포넌트가 여러 개라도 네트워크 요청은 한 번만(Deduping) 발생합니다.
3.2 Optimistic Updates (낙관적 업데이트)
좋아요 기능을 구현한다고 가정해 봅시다. 서버 응답을 기다렸다가 하트 색깔을 바꾸면 반응이 느리게 느껴집니다. React Query는 서버 요청이 성공할 것이라 가정하고 UI를 먼저 업데이트한 후, 실패했을 때 롤백하는 기능을 제공합니다. 이는 사용자 경험(UX)을 극적으로 향상시킵니다.
4. 결론
React Query는 단순한 데이터 패칭 라이브러리가 아닙니다. 애플리케이션의 아키텍처를 단순하게 만들어주는 도구입니다. 복잡한 useEffect를 걷어내고, 선언적인 코드로 비동기 로직을 제어해보세요.