해결된 질문
작성
·
81
·
수정됨
0
안녕하세요!
제가 강의를 모두 수강하고 프로젝트에서 리액트 쿼리를 통해 SSR을 적용하려고 하고 있습니다. 아래 코드는 fetchAPISever
함수를 통해 백엔드 api로부터 데이터를 요청하는 함수입니다. 이때fetchAPIsever
함수는 next/header의 cookies()를 통해 사용자의 토큰이 있으면 토큰을 넣어서 api를 요청하는 함수입니다.
export const getBestAndPendingReviews =
async (): Promise<ReviewePageResponse> => {
const res = await fetchAPIServer('/api/review', 'GET');
if (res.code === 'SUCCESS') {
return res.result;
}
throw new Error(
`리뷰 페이지 데이터 불러오기 실패 ${res.code}-${res.message}`,
);
};
아래 코드는 리뷰 페이지에서 서버 사이드 렌더링으로 보여주기 위해 리액트 쿼리로 Hydration을 적용한 코드입니다.
// src\app\reviews\page.tsx
import {
HydrationBoundary,
QueryClient,
dehydrate,
} from '@tanstack/react-query';
import ReviewDashboard from './_components/ReviewDashboard';
import { getBestAndPendingReviews } from './_lib/getBestAndPendingReviews';
export default async function ReviewsPage() {
const queryClient = new QueryClient();
await queryClient.prefetchQuery({
queryKey: ['reviews', 'best'],
queryFn: getBestAndPendingReviews,
});
const dehydrateState = dehydrate(queryClient);
return (
<HydrationBoundary state={dehydrateState}>
<ReviewDashboard />
</HydrationBoundary>
);
} '
<ReviewDashboard/>
컴포넌트에서 UserInfo 컴포넌트를 반환하도록 설정하고 useQuery 훅을 사용하려 했으나, fetchAPIServer 함수에서 next/headers
를 import하고 있어서 클라이언트 컴포넌트에서 사용할 수 없다는 에러가 발생했습니다. 그러면 SSR을 적용하기 위해서는 getQueryData를 사용해야하는 걸까요..?
import { QueryClient } from '@tanstack/react-query';
import { ReviewePageResponse } from '../_lib/getBestAndPendingReviews';
export default function UserInfo() {
const queryClient = new QueryClient();
const reviews = queryClient.getQueryData<ReviewePageResponse>([
'reviews',
'best',
]);
const { total } = reviews!;
if (!reviews) return <p>리뷰가 없습니다.</p>;
console.log('reviews', reviews);
return <p>작성한 리뷰 {total || 0}</p>;
}
또는 useQuery를 쓰되 쿼리 함수를 Promise.Resolve()로 서버에서 전달 받은 데이터를 받는게 나은가 요?
'use client';
import { useQuery } from '@tanstack/react-query';
export default function UserInfo() {
const { data: reviews, isLoading } = useQuery({
queryKey: ['reviews', 'best'],
queryFn: () => Promise.resolve(), // 서버 데이터 재활용
});
if (isLoading) return <p>Loading...</p>;
if (!reviews) return <p>리뷰가 없습니다.</p>;
const { total } = reviews!;
console.log('reviews', reviews);
return <p>작성한 리뷰 {total || 0}</p>;
}
답변 2
0
안녕하세요, 인프런 AI 인턴입니다. 키키님.
SSR(Server-Side Rendering)을 사용하여 React Query와 함께 데이터를 Fetch하고 Hydration하여 페이지를 구성하려고 하시는군요. 이 과정에서 몇 가지 고려해야 할 사항이 있습니다.
React Query를 사용하여 SSR을 구현할 때 getStaticProps
나 getServerSideProps
와 같은 Next.js 서버 측 데이터 펫칭 방법을 사용하는 것이 일반적입니다. 이 방법을 통해 서버 측에서 데이터를 미리 가져와 클라이언트에 전달할 수 있게 됩니다.
현재 코드를 보면 queryClient.prefetchQuery
로 미리 데이터를 가져오는 과정은 잘 되어있는 것 같습니다. 이 데이터는 dehydrate
를 통해 지연 상태로 만들어지고, 클라이언트 측 컴포넌트(<HydrationBoundary>
)에 전달됩니다.
문제의 핵심은 fetchAPISever
를 통해 서버 측에서 데이터를 가져오는 부분입니다. 이 함수가 서버 전용임에도 클라이언트 컴포넌트에서 사용되면서 발생한 에러는 예상된 상황입니다. 보통 클라이언트에서 useQuery
훅을 사용하여 데이터를 다시 Fetch하도록 해야합니다. 다음과 같은 방법으로 해결해 볼 수 있습니다:
getBestAndPendingReviews
등)에서는 서버 전용 메소드를 사용하여 데이터를 가져옵니다.useQuery
를 사용할 때, 서버에서 받아온 데이터를 초기화 데이터(initialData
)로 설정하여 네트워크 요청을 최소화할 수 있습니다.네트워크 탭에서 Loading..만 발생하는 경우는 데이터를 클라이언트에서 다시 요청하게 되는 상황일 수 있습니다. SSR 적용 여부를 확인하려면 브라우저 네트워크 패널에서 초기 HTML 응답에 실제 데이터가 포함되어 있는지를 살피면 됩니다.
아래 두 게시물에서 비슷한 문제 및 해법을 다루었습니다:
- “개인 팀프로젝트 중에 NextJS + react-query 관련 궁금증입니다.”
- “react-query ssr설정”
저는 질문자님의 이해를 돕고자 지식공유자님의 기존 답변을 참고하여 유사한 답변 링크를 추천해드리고 있습니다.
현재 베타 기능으로 답변이 만족스럽지 않을 수 있는 점 양해 부탁드립니다. 🙏
추가적으로 궁금한 점이 있으시면, 이어서 질문해 주세요. 곧 지식공유자께서 답변해 주실 것입니다.
답변 감사합니다! 서버에서 실행할 함수와 클라이언트 환경에서 실행할 함수를 분리하니 잘 작동이 됩니다. 그럼 리뷰 페이지에서 서버 환경에서
getBestAndPendingReviewsServer
를 호출하여 데이터를 패칭하고 react Query의prefetchQuery
와dehydrate
를 통해 데이터를 클라이언트에 전달하는 역할을 한다는 것은 이해했습니다. 그럼<UserInfo/>
컴포넌트에서 useQuery로 쿼리 함수가getBestAndPendingReviews
로 적용되어 있지만 실제로는 해당 쿼리 함수를 실행하지 않고 Hydration된 데이터를 그대로 사용해서 SSR이 적용되는 것으로 이해했는데 이게 맞을까요?