Next.js의 서버 컴포넌트에서 prefetchQuery를 사용하기 위해서는 queryClient가 필요하다.
매 컴포넌트마다 queryClient를 생성하면 여러 서버 컴포넌트에서 동일한 queryClient에 접근해야될 때 비효율적이므로, queryClient 컴포넌트를 따로 만들어서 관리하는 것이 좋다.
그런데 서버 컴포넌트와 클라이언트 컴포넌트에서 queryClient를 호출하는 방식이 다르다.
클라이언트에서 쿼리 호출용
'use client';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import { ReactNode, useState } from 'react';
interface QueryProviderProps {
children: ReactNode;
}
export const QueryProvider = ({ children }: QueryProviderProps) => {
const [queryClient] = useState(
() =>
new QueryClient({
defaultOptions: {
queries: {
refetchOnWindowFocus: false,
retry: 1,
staleTime: 1000 * 60 * 5,
},
},
}),
);
return <QueryClientProvider client={queryClient}>{children}</QueryClientProvider>;
};
이 provider로 전체를 감싸주면, 이 Next.js 프로젝트 안의 클라이언트 컴포넌트에서는 일일히 queryClient를 직접 만들 필요가 없다.
이 provider는 useState를 사용하기 때문에 서버전용 provider는 만들 수 없다.
서버 컴포넌트에서 쿼리 호출용
import { QueryClient } from '@tanstack/react-query';
import { cache } from 'react';
export const getServerQueryClient = cache(
() =>
new QueryClient({
defaultOptions: {
queries: {
staleTime: 60 * 1000,
gcTime: 5 * 60 * 1000,
},
},
}),
);
export default async function MyPage() {
const queryClient = getServerQueryClient();
const dehydratedState = dehydrate(queryClient);
return (
<HydrationBoundary state={dehydratedState}>
...
그래서 SSR 환경에서 prefetchQuery를 사용할 경우엔 위 컴포넌트가 추가적으로 있어야한다.
클라이언트용과 다른 점은 react의 cache 함수를 이용한다는 것이다.
그럼 여기서 cache의 기능은 무엇일까?
1. 요청별로 범위가 지정되어 사용자 간 데이터 격리 보장
2. 동일한 요청 내에서는 항상 같은 QueryClient 인스턴스 사용
3. 요청당 하나의 QueryClient만 생성되어 메모리 효율성 증가
그럼 클라이언트에서는?
React의 상태 관리 메커니즘을 통해 컴포넌트 라이프사이클 동안 QueryClient 인스턴스를 유지하기 때문에 cache를 사용할 필요가 없다.
'Next.js' 카테고리의 다른 글
[Next.js] SSR 환경에서의 데이터 공유(캐싱, 전역 상태 관리) (0) | 2025.04.20 |
---|---|
[Next.js] 프로젝트 초기 세팅을 해보자! (0) | 2025.04.06 |
React는 라이브러리, Next.js는 프레임워크? (0) | 2025.03.23 |
[리팩토링]Next.js 프로젝트 리팩토링 기록 정리 (0) | 2025.02.27 |