❓ prefetchQuery란?
- React Query에서 제공하는 데이터 프리페칭 메커니즘으로,
사용자의 실제 데이터 요청 전에 미리 데이터를 가져와 캐시에 저장하는 기능
-> 사용자가 해당 데이터를 필요로 할 때 즉시 보여줄 수 있음!
▶ 기본 사용 예시
import { QueryClient } from '@tanstack/react-query'
import { fetchUserData } from './api'
const queryClient = new QueryClient()
queryClient.prefetchQuery({
queryKey: ['user', 1],
queryFn: () => fetchUserData(1),
})
❗ prefetchQuery가 필요한 이유
✅ UX 개선
- 페이지 전환 시 API 요청을 기다릴 필요 없이 즉시 데이터를 렌더링
- 특히 탭 UI, 마우스 오버, 페이지 이동 시 효과적
✅ 성능 최적화
- 불필요한 API 호출을 줄여 서버 부하 감소
- Next.js 같은 SSR 환경에서 dehydrate()와 함께 사용시 초기 페이지에 데이터를 미리 채워 SEO 개선 가능
💥 prefetchQuery 사용 시 주의사항
1️⃣ 적절한 staleTime 설정 필요
2️⃣ 불필요한 prefetch 방지
-> 너무 많은 데이터를 미리 가져오면 네트워크 낭비 & 성능 저하
->사용자 행동을 예측하여 필요한 데이터만 prefetch
💠 prefetchQuery 활용 예시
1️⃣ 페이지 이동 시, 다음 페이지 데이터 미리 불러오기
-> 사용자가 이동할 가능성이 높은 페이지의 데이터를 미리 가져와서 로딩 시간을 줄일 수 있음
2️⃣ 마우스 오버(hover) 시 데이터 미리 가져오기
-> 사용자가 버튼을 클릭했을 때 로딩 없이 바로 상세 정보를 제공
3️⃣ 탭 UI에서 미리 데이터 로딩
-> 사용자가 다른 탭을 누를 가능성이 높을 때 미리 데이터 불러오기
4️⃣ 무한 스크롤 (Infinite Scroll)에서 다음 페이지 미리 로드
▶ 무한 스크롤 사용 예시
const { data, fetchNextPage } = useInfiniteQuery({
queryKey: ['posts'],
queryFn: fetchPosts,
getNextPageParam: (lastPage, pages) => lastPage.nextCursor,
})
useEffect(() => {
if (data?.pages.length) {
queryClient.prefetchQuery({
queryKey: ['posts', data.pages.length + 1],
queryFn: () => fetchPosts({ page: data.pages.length + 1 }),
})
}
}, [data])
🚩 실제 프로젝트에서 사용했던 코드 (Next.js)
import { getQueryClient } from "@/hooks/getQueryClient"
import Main from "@/components/main/myhome/Main"
import postMyRanking from "@/services/main/ranking/postMyRanking"
import { HydrationBoundary, dehydrate } from "@tanstack/react-query"
const Page = async () => {
const themeIdx = [1, 4, 7]
const queryClient = getQueryClient()
await Promise.all(
themeIdx.map((idx) =>
queryClient.prefetchQuery({
queryKey: ["myRanking", idx],
queryFn: () => postMyRanking(idx),
}),
),
)
const dehydratedState = dehydrate(queryClient)
return (
<HydrationBoundary state={dehydratedState}>
<Main />
</HydrationBoundary>
)
}
export default Page
Next.js 프로젝트에서 prefetchQuery를 사용한 이유는 메인페이지를 렌더링하기 전에 사용자의 모든 랭킹정보를 미리 불러오기 위해서였다.
이를 통해 사용자에게 정보를 즉시 제공하여 UX를 향상시키고, 불필요한 API 호출도 줄이면서 SSR의 장점을 최대한 활용하고자 했다.
이를 위해 dehydratedState를 정의하고 메인페이지 컴포넌트를 HydrationBoundary로 감쌌는데,
이는 서버에서 미리 가져온 데이터를 직렬화하여 클라이언트에 전달하는 방식이다.
HydrationBoundary를 통해 클라이언트의 React Query가 이 데이터를 즉시 사용할 수 있게 되었다.
결과적으로 이 방식으로 SSR을 성공적으로 구현할 수 있었다! 👏
그렇다면, Next.js(SSR) 대신 React(CSR)를 사용할 경우에는 어떻게 될까?
✅ React(CSR)에서 prefetchQuery 사용
- 사용자가 특정 동작을 하기 전에 prefetchQuery를 사용해 미리 데이터를 캐시에 저장하는 효과 (only)
- 그리고 초기 로딩 시 데이터를 서버에서 미리 가져와 주입하는 과정이 없기 때문에 dehydrate가 필요하지 않음!
❔ SSR에서 dehydrate가 필요한 이유
- 서버에서 가져온 데이터를 클라이언트에 그대로 전달 불가.
그래서 hydrate를 안하면 클라이언트에서 다시 데이터를 요청해야함.
-> dehydrate를 사용하면 데이터를 직렬화하여 HTML과 함께 클라이언트에 전달 가능 -> 불필요한 요청 감소!
결론은 SSR에서 React Query의 prefetchQuery를 사용할 땐 무조건 dehydrate과정을 거쳐야한다는 것!
안 그러면 React Query의 캐시를 사용할 수 없어서 prefetch를 하는 것이 아무런 의미가 없다...
'React' 카테고리의 다른 글
[React] useMemo, useCallback (+캐싱) (0) | 2025.03.30 |
---|---|
[React] useCallback (0) | 2025.03.27 |
useEffect의 의존성 배열 (0) | 2024.03.10 |
useRef (0) | 2024.03.10 |
React Query (0) | 2024.03.03 |