Next 13 + React Query로 서버 사이드 데이터 프리패칭 구현

윤병현·2024년 6월 21일
1

FeedB

목록 보기
4/10
post-thumbnail

Next 13버전이 나오면서 RSC(React Server Component) 개념에 대해 새롭게 추가되었습니다.

RSC란?

서버 컴포넌트는 React 컴포넌트를 서버에서 렌더링하는 방식으로, 클라이언트가 요청을 보내면 서버에서 컴포넌트를 렌더링하여 완성된 HTML을 클라이언트에게 전달합니다. 이는 기존의 클라이언트 사이드 렌더링(CSR) 및 서버 사이드 렌더링(SSR)과는 다르게 작동하며, 새로운 기능과 이점을 제공합니다.

import { fetchData } from 'path/to/api';

export default async function Page() {
  const data = await fetchData();

  return (
    <div>
      <h1>Server Component Example</h1>
      <pre>{JSON.stringify(data, null, 2)}</pre>
    </div>
  );
}

위의 예시에서 fetchData 함수는 서버에서 데이터를 가져오며, 이를 서버 컴포넌트에서 직접 사용합니다. 이 데이터는 클라이언트에게 완성된 HTML로 전달됩니다.

예시와 같이 서버에서 데이터를 가져와 다른 컴포넌트로 전달을 해줄 수가 있는데 이번 프로젝트에서는 React Query를 사용하기로 팀원들과 결정했기 때문에 서버 컴포넌트 대신 React Query를 사용해 데이터를 prefetching 할 수 있는 방법을 찾아보았습니다.

React Query 프리패칭

아직 Next.Js에서는 공식적으로 React Query를 사용해 SSR를 할 수 있도록 지원을 안 해주기 때문에 React Query를 사용해 데이터를 SSR과 유사한 환경을 제공할 수 있도록 하기 위해 React Query 공식문서를 찾아보았습니다. 공식문서에는 아래와 같이 두가지 방법이 있었습니다.

적용 방법

initialData 또는 <HydrationBoundary> 를 사용하는 두 가지 프리패치 접근 방식 모두 앱 디렉터리 내에서 사용할 수 있습니다 .

서버 구성 요소의 데이터를 프리페치하고 초기화 데이터를 클라이언트 구성 요소로 드릴링합니다.

  • 간단한 경우에는 빠르게 설정 가능
  • 여러 계층의 클라이언트 구성 요소를 통해 드릴을 준비해야 할 수도 있음
  • 동일한 쿼리를 사용하여 여러 클라이언트 구성 요소에 드릴을 적용해야 할 수도 있습니다.
  • 쿼리 다시 가져오기는 데이터가 서버에서 프리페치된 시점이 아닌 페이지가 로드되는 시점을 기반으로 합니다.

<HydrationBoundary>를 사용하여 서버에서 쿼리를 프리페치하고, 캐시를 탈수하고 클라이언트에서 다시 수화합니다.

  • 약간 더 많은 설정이 필요합니다.
  • 드릴을 지탱할 필요가 없습니다.
  • 쿼리 다시 가져오기는 쿼리가 서버에서 프리페치된 시점을 기준으로 합니다.

이 방법 중 저는 <HydrationBoundary>를 사용하여 적용시켜보려고 합니다. 위에 설명에 나와있듯이 이 방법을 쓰기 위해서는 따로 몇가지에 설정을 해줘야합니다.

설정 1

provideers.ts

"use client";

import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
import { ReactQueryDevtools } from "@tanstack/react-query-devtools";
import React, { ReactNode } from "react";

export default function Providers({ children }: { children: ReactNode }) {
  const [queryClient] = React.useState(() => new QueryClient());

  return (
    <QueryClientProvider client={queryClient}>
      {children}
      <ReactQueryDevtools initialIsOpen={false} />
    </QueryClientProvider>
  );
}

layout.ts

import Providers from "@/app/_queryFactory/providers";
import Header from "@/app/_components/Header/Header";
import type { Metadata } from "next";
import "@/app/_styles/globals.css";

export const metadata: Metadata = {
  title: "FeedB",
  description: "FeedBd에 오신 걸 환영합니다",
};

export default function MainPageLayout({children,}: Readonly<{children: React.ReactNode}>) {
return (
  <Providers>
    <div id="modal" />
    <Header />
    {children}
  </Providers>
 );
}

react-query 패키지에서 제공하는 훅은 QueryClient를 context에서 가져와야 합니다. <QueryClientProvider>로 컴포넌트 트리를 감싸고 QueryClient 인스턴스를 전달해줘여합니다.

설정 2

getQueryClient.ts

import { QueryClient } from "@tanstack/react-query";
import { cache } from "react";

const getQueryClient = cache(() => new QueryClient());
export default getQueryClient;

QueryClient의 요청 범위 싱글톤 인스턴스를 생성하세요. 이는 데이터가 다른 사용자와 요청 간에 공유되지 않도록 하며, 각 요청마다 QueryClient를 한 번만 생성합니다.

설정 3

import { dehydrate, HydrationBoundary } from "@tanstack/react-query";
import getQueryClient from "../_queryFactory/getQueryClient";

async function MainPage() {
  const queryClient = getQueryClient();

  await queryClient.prefetchQuery({
    queryKey: ["project", "list", "projectList"],
    queryFn: async () => {
      const response = projectApi.getprojectList({ page: 1, size: 12 });
      return response;
    },
  });

  const dehydratedState = dehydrate(queryClient);

  return (
    <HydrationBoundary state={dehydratedState}>
      <main className="mx-auto mt-[100px] grid w-[1200px] grid-cols-[230px_minmax(976px,_1fr)] grid-rows-[100px_minmax(800px,_1fr)]">
        <SelectStack />
      </main>
    </HydrationBoundary>
  );
}

export default MainPage;

데이터를 서버 컴포넌트에서 가져오되, 클라이언트 컴포넌트에서 미리 가져온 쿼리를 사용하는 것보다 더 높은 위치에서 가져와야합니다. 이렇게 하면 미리 가져온 쿼리를 컴포넌트 트리의 더 깊은 모든 컴포넌트에서 사용할 수 있습니다.

  • QueryClient 싱글톤 인스턴스를 가져옵니다.
  • 클라이언트의 prefetchQuery 메서드를 사용하여 데이터를 미리 가져오고, 완료될 때까지 기다립니다.
  • dehydrate를 사용하여 쿼리 캐시에서 미리 가져온 쿼리의 상태를 얻습니다.
  • 미리 가져온 쿼리가 필요한 컴포넌트 트리를 <HydrationBoundary>로 감싸고, 이를 dehydrate된 상태와 함께 제공합니다.
  • 여러 서버 컴포넌트에서 데이터를 가져오고, 여러 곳에서 <HydrationBoundary>를 사용할 수 있습니다.

참고

https://tanstack.com/query/v4/docs/framework/react/guides/ssr 리엑트 쿼리 공식문서

profile
프론드엔드 개발자

0개의 댓글

관련 채용 정보