[React] React.js 강좌 20. React Query와 Router 결합으로 페이지 전환 성능 최적화하기
1. 왜 라우터와 React Query를 함께 고려해야 할까
React Router는 페이지 간의 UI 전환을 담당하고,
React Query는 각 페이지의 데이터 로딩과 캐싱을 담당합니다.
이 두 가지를 잘 결합하면
페이지를 이동할 때마다 새로 데이터를 불러오지 않아도 되고,
사용자는 즉각적인 반응성을 느낄 수 있습니다.
예를 들어
대시보드 → 설정 → 통계 페이지로 이동하더라도
이미 캐시에 있는 데이터를 재활용하면 로딩 없이 전환이 가능합니다.
2. 예제 시나리오
이번 예제는 다음 구조를 가정합니다.
/dashboard
├── /stats
├── /notifications
└── /settings
각 페이지는 서버로부터 데이터를 받아오며,
React Query를 통해 캐시 관리가 이루어집니다.
3. React Query 전역 설정
먼저 QueryClient를 생성할 때 기본 옵션을 설정합니다.
// queryClient.js
import { QueryClient } from '@tanstack/react-query';
const queryClient = new QueryClient({
defaultOptions: {
queries: {
retry: 1, // 실패 시 한 번 재시도
refetchOnWindowFocus: false, // 포커스 시 자동 새로고침 비활성화
staleTime: 1000 * 60 * 3, // 3분 동안 캐시 유지
},
},
});
export default queryClient;
index.js에서 이 클라이언트를 전역에 등록합니다.
import { QueryClientProvider } from '@tanstack/react-query';
import queryClient from './queryClient';
import App from './App';
export default function Root() {
return (
<QueryClientProvider client={queryClient}>
<App />
</QueryClientProvider>
);
}
4. 페이지별 React Query 적용
예를 들어 통계 페이지(DashboardStats.jsx)에서 서버 데이터를 가져오는 코드는 다음과 같습니다.
// DashboardStats.jsx
import { useQuery } from '@tanstack/react-query';
import api from './api';
export default function DashboardStats() {
const { data, isLoading, isError } = useQuery({
queryKey: ['stats'],
queryFn: async () => {
const res = await api.get('/dashboard/stats');
return res.data;
},
});
if (isLoading) return <p>통계 데이터를 불러오는 중입니다...</p>;
if (isError) return <p style={{ color: 'red' }}>데이터 로딩 실패</p>;
return (
<div>
<h3>대시보드 통계</h3>
<p>총 방문자 수: {data.visitors}</p>
<p>가입자 수: {data.users}</p>
<p>활성 세션 수: {data.sessions}</p>
</div>
);
}
React Query는 ['stats']라는 키로 데이터를 캐싱합니다.
다시 /dashboard/stats로 돌아와도 API를 재호출하지 않습니다.
5. 페이지 이동 시 캐시 활용
React Router를 통해 다른 페이지로 이동할 때,
기존의 데이터가 즉시 표시되도록 캐시를 활용합니다.
import { Link } from 'react-router-dom';
function Navbar() {
return (
<nav>
<Link to="/dashboard/stats">통계</Link> |{" "}
<Link to="/dashboard/notifications">알림</Link> |{" "}
<Link to="/dashboard/settings">설정</Link>
</nav>
);
}
사용자가 한 번이라도 페이지를 방문했다면,
React Query가 자동으로 캐시 데이터를 보여주고, 백그라운드에서 새 데이터를 가져옵니다.
이 과정을 Stale-While-Revalidate(SWR) 전략이라고 부릅니다.
6. 페이지 사전 로드 (Prefetch)
페이지 전환 시 로딩 없이 즉시 데이터를 표시하려면,
React Query의 prefetchQuery 기능을 사용할 수 있습니다.
예를 들어 사용자가 링크 위에 마우스를 올렸을 때 미리 데이터를 불러옵니다.
import { useQueryClient } from '@tanstack/react-query';
import { Link } from 'react-router-dom';
import api from './api';
function Navbar() {
const queryClient = useQueryClient();
const prefetchStats = async () => {
await queryClient.prefetchQuery({
queryKey: ['stats'],
queryFn: async () => {
const res = await api.get('/dashboard/stats');
return res.data;
},
});
};
return (
<nav>
<Link to="/dashboard/stats" onMouseEnter={prefetchStats}>통계</Link>
{" | "}
<Link to="/dashboard/notifications">알림</Link>
{" | "}
<Link to="/dashboard/settings">설정</Link>
</nav>
);
}
이렇게 하면 사용자가 “통계” 페이지로 이동할 때
데이터가 이미 캐시에 있어 즉시 렌더링됩니다.
7. 페이지 이동 간 로딩 최적화
라우터 전환 중에도 자연스러운 UX를 유지하기 위해
React Router의 useNavigation() 훅을 사용할 수 있습니다.
import { useNavigation } from 'react-router-dom';
function LoadingIndicator() {
const navigation = useNavigation();
const isNavigating = navigation.state !== 'idle';
return isNavigating ? <p>페이지 이동 중...</p> : null;
}
이 컴포넌트를 App.js 상단에 두면,
라우트 전환 시 로딩 인디케이터가 표시됩니다.
8. 캐시 무효화 (Invalidate)
만약 설정 페이지에서 데이터를 수정했다면,
다음과 같이 캐시를 무효화하여 대시보드 데이터를 갱신할 수 있습니다.
import { useMutation, useQueryClient } from '@tanstack/react-query';
import api from './api';
function Settings() {
const queryClient = useQueryClient();
const mutation = useMutation({
mutationFn: (newSettings) => api.post('/settings', newSettings),
onSuccess: () => {
queryClient.invalidateQueries(['stats']); // 통계 데이터 갱신
},
});
return (
<form onSubmit={(e) => { e.preventDefault(); mutation.mutate({ theme: 'dark' }); }}>
<button type="submit">저장</button>
</form>
);
}
이렇게 하면 설정을 변경한 직후,
다음에 대시보드 페이지로 돌아가면 최신 데이터가 자동으로 반영됩니다.
9. 전체 구조 요약
구성요소 역할 설명
| React Router | 페이지 전환 | URL 기반 화면 분기 |
| React Query | 데이터 관리 | API 요청, 캐싱, 자동 리페칭 |
| PrefetchQuery | 사전 로딩 | 페이지 이동 전에 데이터 미리 요청 |
| InvalidateQueries | 갱신 관리 | 변경된 데이터 자동 업데이트 |
| StaleTime | 캐시 정책 | 일정 시간 동안 네트워크 요청 최소화 |
10. 마무리
이번 강의에서는 React Router와 React Query를 결합하여
페이지 전환 시 즉각적인 반응성을 구현하는 방법을 배웠습니다.
핵심 포인트:
- 페이지 간 이동 시 React Query 캐시를 활용하면 API 호출 최소화
- prefetchQuery()로 미리 데이터를 가져와 UX 개선
- invalidateQueries()로 데이터 갱신 제어
- staleTime을 조정해 캐시 유지 시간 관리
이제 여러분의 애플리케이션은 페이지 전환 시에도
끊김 없는 자연스러운 사용자 경험을 제공할 수 있습니다.
다음 강의에서는 React 애플리케이션의 전역 에러 처리와 인터셉터 기반 인증 흐름 관리를 다룰 예정입니다.