React-qeury + Next.js :: Prefetching (SSR)

getServerSideProps()를 이용해서 클라이언트 서버단에서 data를 fetching하고, 그 데이터를 prefetching 하는 방법에 대해 알아본다. 이 방법을 사용하면, 최초 화면이 렌더링 될 때는 클라이언트 서버에서 data를 fetching 하기 때문에 API 서버와 통신하는 이력을 볼 수 없을 것이다. 이후 같은 query key의 데이터를 다시 fetching 하면 클라이언트에서 data를 fetching 한다. (해당 query가 stale 상태일 때)

  1. react-query 설정
    SSR을 위한 설정에서 반드시 필요한 것은 Hydrate 이다. 공식문서에서 제시하는 방법대로 설정한다.

import "../styles/globals.css";
import type { AppProps } from "next/app";
import { Hydrate, QueryClient, QueryClientProvider } from "react-query";
import { ReactQueryDevtools } from "react-query/devtools";

const queryClient = new QueryClient();

function MyApp({ Component, pageProps }: AppProps) {
  return (
    <QueryClientProvider client={queryClient}>
      <Hydrate state={pageProps.dehydratedState}> // << 이 부분
        <Component {...pageProps} />
        <ReactQueryDevtools />
      </Hydrate>
    </QueryClientProvider>
  );
}

export default MyApp;
  1. component
    Next.js에서 SSR을 하기 위해서는 컴포넌트 파일 내에서 getServerSideProps()를 사용한다. 해당 함수는 Next.js 클라이언트 서버 단에서 실행된다. 프로세스는 다음과 같다.

    [queryClient 생성] -> [queryClient에서 prefetchQeury()를 이용해서 data fetching] -> [props에서 dehydratedState: dehydrate(qc)로 return] -> [컴포넌트 단에서 같은 query key로 useQuery()] -> [{data}를 활용해서 rendering]

export const getServerSideProps: GetServerSideProps = async (context) => {
  const { id } = context.query;
  const qc = new QueryClient();
  await qc.prefetchQuery(
    ["person"],
    async () => {
      const { data } = await axios.get(`http://localhost:3001/person/${id}`);
      return data;
    }
  );

  return {
    props: {
      name: "with",
      id,
      dehydratedState: dehydrate(qc), // 반드시 dehydratedState 이어야 함
    },
  };
};
  1. 적용 확인

적용 후 컴포넌트를 Refresh 하면, 최초에 데이터 fetching이 network에 보이지 않는 것을 확인 할 수 있다. 클라이언트 서버단에서 데이터 fetching이 이루어 졌기 때문이다.

  1. 전체 코드
import axios from "axios";
import { GetServerSideProps } from "next";
import React from "react";
import { dehydrate, QueryClient, useQuery } from "react-query";

const Item = ({ id }: any) => {
  const { data } = useQuery(
    ["person"],
    async () => {
      const { data } = await axios.get(`http://localhost:3001/person/${id}`);
      return data;
    },
    {
      staleTime: 3000,
    }
  );

  return (
    <div>
      <div>{data?.name}</div>
      <div>{data?.age}</div>
    </div>
  );
};

export const getServerSideProps: GetServerSideProps = async (context) => {
  const { id } = context.query;
  const qc = new QueryClient();
  await qc.prefetchQuery(
    ["pers1on"],
    async () => {
      const { data } = await axios.get(`http://localhost:3001/person/${id}`);
      return data;
    },
    {
      staleTime: 10000,
    }
  );

  return {
    props: {
      name: "with",
      id,
      dehydratedState: dehydrate(qc),
    },
  };
};

export default Item;

좋은 웹페이지 즐겨찾기