NextJs React-Query Prisma

OkGyoung·2023년 12월 4일
0

오늘은 NextJs React-Query Prisma을 이용해 SSR 구현을 만든 과정을 정리한다.

먼저 각 모듈을 사용한 이유는

  1. NextJs: SEO최적화, Image, Link등 최적화 후에 vercel을 통한 무료배포

  2. React-Query: 적절한 캐싱, DB를 통한 상태관리

  3. Prisma: DB연동 백엔드 서버리스로 구현

이다.

NextJs는 14.0.1, React-Query는 5.8.9, Prisma는 5.5.2버젼을 이용했고 DB는 mongoDB를 사용했다.

먼저 Provider를 통해서 React-Query를 사용할 곳을 묶어주어여한다.

RQProvider.tsx

"use client";

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

interface Props {
  children: ReactNode;
}
export default function RQProvider({ children }: Props) {
  const [queryClient] = React.useState(() => new QueryClient());
  return (
    <QueryClientProvider client={queryClient}>{children}</QueryClientProvider>
  );
}

또 getQueryClient, Hydrate를 만들어야한다.

getQueryClient.ts

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

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

Hydrate.tsx

"use client";
import React from "react";
import {
  HydrationBoundary,
  HydrationBoundaryProps,
} from "@tanstack/react-query";

function Hydrate(props: HydrationBoundaryProps) {
  return <HydrationBoundary {...props} />;
}

export default Hydrate;

SEO를 최적화하기위해 서버에서 필요한 데이터를 받고 이후 클라이언트에서Hydrate작업 시 필요한 데이터를 바로 넘겨주는 방식이다. 여기서 prefetchQuery 통해서 미리 데이터를 받는 것이 핵심이다.

먼저 Prisma연결과 필요한 api제작은 이전 NextAuth를 보면 찾을 수 있다.

컴포넌트 사용page.tsx

import { dehydrate } from "@tanstack/query-core";
import Hydrate from "./utils/Hydrate";
import { getQueryClient } from "./utils/getQueryClient";
import Test from "./component/Test";
import { getClub } from "./utils/getClub";

export default async function Home() {
  const client = getQueryClient();
  await client.prefetchQuery({
    queryKey: ["club"],
    queryFn: () => getClub(),
  });
  const dehydratedState = dehydrate(client, {
    shouldDehydrateQuery: () => true,
  });
  return (
    <main className="flex min-h-screen flex-col items-center pl-[88px] pr-[32px]">
      <Hydrate state={dehydratedState}>
        <Test />
      </Hydrate>
    </main>
  );
}

본인은 Test라는 컴포넌트를 만들었다 위처럼 prefetchQuery를 통해 미리 데이터를 받아오고 Hydrate와 dehydratedState를 통해 적절한 데이터를 넘겨줄 준비를 한다. 이후

Test.tsx

"use client";

import { useQuery } from "@tanstack/react-query";
import { getClub } from "../utils/getClub";

const Test = () => {
  const { data } = useQuery({
    queryKey: ["club"],
    queryFn: () => getClub(),
    staleTime: 1000 * 60,
  });
  return (
    <div>
      {data?.map((el, idx) => (
        <p key={`${idx}p`}>{el.player.name}</p>
      ))}
    </div>
  );
};

export default Test;

위처럼 전에 미리 받아온 데이터를 사용하는 컴포넌트를 만든다 여기서 핵심은 queryKey, staleTime인데 쿼리키를 통해 독립적으로 각 데이터를 관리하고 staleTime만큼 캐싱하고 있는다

위 방법을 사용하면 SEO를 최적화하면서 적절한 데이터를 받아올 수 있고 또 Infinite Queries를 사용해 무한 스크롤로 응용할 수도 있다.

! 과정에서 오류가 생겼던점 can be passed to client components from server components. classes or null prototypes are not supported

작업을 진행하면서 위와 같은 오류가 계속 발생했다. 직역하면 클라이언트, 서버 컴포넌트 사이에 데이터 교환에서 데이터 타입에 의해 생기는 문제였는데 예상외로 해결법이 데이터를 받아오는 함수 위에 예제라면 getClub()에서 url입력 시 베이스 url을 건너뛰고 작성하였는데 그로 인해 발생한 오류였다.

profile
이유를 생각하는 개발자

0개의 댓글