React Query는 클라이언트 상태 관리와 비동기 데이터 처리를 효율적으로 처리할 수 있는 도구로, 특히 데이터를 캐싱하고 적절한 시점에 갱신하는 기능이 강력합니다. 이 글에서는 캐시타임(Cache Time), 스테일타임(Stale Time), 포커스 속성(refetchOnWindowFocus)에 대해 깊이 이해하고, 이를 활용하여 최적의 데이터 페칭 로직을 구현하는 방법을 소개합니다.
캐시타임은 React Query가 데이터를 메모리에 유지하는 기간을 의미합니다. 데이터가 더 이상 화면에서 사용되지 않더라도, 지정된 캐시타임 동안 메모리에 남아 있어 다시 요청하지 않고 재사용할 수 있습니다.
useQuery('key', fetchFunction, {
cacheTime: 1000 * 60 * 10, // 10분 동안 캐시 유지
});
스테일타임은 데이터가 "최신 데이터"로 간주되는 시간을 의미합니다. 이 시간이 지나면 데이터가 "stale(오래된)" 상태로 간주되고, 다음 액션(리패칭 등) 시 새 데이터를 가져옵니다.
useQuery('key', fetchFunction, {
staleTime: 1000 * 60 * 5, // 5분 동안 데이터를 최신으로 간주
});
포커스 속성은 브라우저 창(탭)이 다시 포커스될 때 데이터를 리패칭할지 여부를 제어합니다.
useQuery('key', fetchFunction, {
refetchOnWindowFocus: false, // 포커스 시 리패칭 비활성화
});
import { useQuery } from 'react-query';
const fetchUserData = async () => {
const response = await fetch('/api/user');
return response.json();
};
const UserProfile = () => {
const { data, isLoading, isError } = useQuery('user', fetchUserData, {
cacheTime: 1000 * 60 * 10, // 10분 동안 캐시 유지
staleTime: 1000 * 60 * 5, // 5분 동안 데이터를 최신 상태로 간주
refetchOnWindowFocus: true, // 포커스 시 리패칭 활성화
});
if (isLoading) return <p>Loading...</p>;
if (isError) return <p>Error loading data</p>;
return (
<div>
<h1>{data.name}</h1>
<p>{data.email}</p>
</div>
);
};
export default UserProfile;
속성 | 캐시타임 (cacheTime) | 스테일타임 (staleTime) |
---|---|---|
의미 | 데이터를 메모리에 유지하는 시간 | 데이터를 최신으로 간주하는 시간 |
기본값 | 5분 (300000ms) | 0ms |
주요 사용 시점 | 페이지 전환 시 캐시를 유지하고 서버 요청을 줄이고 싶을 때 | 데이터가 자주 갱신되지 않고, 실시간성이 중요하지 않을 때 |
영향 | 데이터가 캐시에 있는 동안 새 요청 없이 반환 | 스테일 상태가 되기 전까지 추가 패칭을 수행하지 않음 |
React Query의 캐시타임, 스테일타임, 포커스 속성을 적절히 활용하면 데이터 페칭 로직을 효율적으로 관리할 수 있습니다.
캐시타임과 스테일타임은 초기 데이터를 프리패칭(prefetch)한 후에도 영향을 미칩니다.
// Prefetch example
import { QueryClient, QueryClientProvider, useQuery, useQueryClient } from 'react-query';
const queryClient = new QueryClient();
queryClient.prefetchQuery('user', fetchUserData, {
staleTime: 1000 * 60 * 10, // 10분 동안 최신 데이터로 간주
});
useQuery('key', fetchFunction, {
refetchOnWindowFocus: true,
refetchOnReconnect: true, // 네트워크 재연결 시 리패칭
});
캐싱 전략은 queryKey와 밀접하게 연관됩니다. 잘못된 queryKey 설계는 캐싱의 장점을 무효화할 수 있습니다.
useQuery(['user', userId], fetchUserData);
useQuery(['posts', page], fetchPosts);
React Query는 개발 중 데이터의 캐싱 상태, 스테일 상태 등을 실시간으로 확인할 수 있는 Devtools를 제공합니다.
import { ReactQueryDevtools } from '@tanstack/react-query-devtools';
function App() {
return (
<QueryClientProvider client={queryClient}>
<YourApp />
<ReactQueryDevtools initialIsOpen={false} />
</QueryClientProvider>
);
}
React Query는 일정 간격으로 데이터를 자동 갱신할 수 있는 기능도 제공합니다.
useQuery('key', fetchFunction, {
refetchInterval: 1000 * 60, // 1분마다 데이터 갱신
refetchIntervalInBackground: true, // 비활성 상태에서도 실행
});
React Query는 동일한 컴포넌트 내 여러 쿼리 요청을 배치(batch) 처리하여 네트워크 성능을 향상할 수 있습니다.
const queryClient = new QueryClient({
defaultOptions: {
queries: {
useErrorBoundary: true,
retry: 1,
},
},
});
useErrorBoundary: true: 에러가 발생하면 컴포넌트 내에서 처리하지 않고, ErrorBoundary 컴포넌트에 에러를 전달합니다.
retry: 1: 쿼리 요청 실패 시 최대 1번 재시도합니다.
import { useQuery, QueryClient, QueryClientProvider } from 'react-query';
const queryClient = new QueryClient({
defaultOptions: {
queries: {
useErrorBoundary: true,
retry: 1,
},
},
});
function Dashboard() {
const { data: userInfo } = useQuery('userInfo', fetchUserInfo);
const { data: orders } = useQuery('orders', fetchOrders);
const { data: notifications } = useQuery('notifications', fetchNotifications);
return (
<div>
<h1>Dashboard</h1>
<div>{userInfo?.name}</div>
<div>{orders?.length} Orders</div>
<div>{notifications?.length} Notifications</div>
</div>
);
}
export default function App() {
return (
<QueryClientProvider client={queryClient}>
<Dashboard />
</QueryClientProvider>
);
}