본문 바로가기
카테고리 없음

Tanstack query에서 Hydration - SSR

by riversun1 2024. 7. 10.

 

 Next.js로 프로젝트를 진행하다가 Tanstack query를 사용시 클라이언트 컴포넌트가 된다는 것을 알았다.

Tanstack query를 쓰더라도 서버 컴포넌트로 만들 수 없을까? 하는 생각이 들었다.

 

그러다가 나는 왜 굳이 서버 컴포넌트를 고집하는가? 하는 생각이 들면서 다시 정리를 해봤다.

 

 

[ 서버 컴포넌트를 사용하는 이유 ]

  1. SEO 최적화
    • 서버에서 HTML을 생성해 클라이언트로 전달하면 검색 엔진 크롤러가 더 쉽게 페이지 내용을 인덱싱 가능. 이는 검색 엔진 최적화(SEO)에 도움이 됨.
  2. 빠른 초기 로드 속도
    • 클라이언트에서 JavaScript가 실행되기 전에 미리 렌더링된 HTML을 제공함으로써 초기 로드 속도가 빨라짐. 사용자는 더 빠르게 콘텐츠를 확인 가능.
  3. 데이터 페칭 효율성
    • 서버에서 데이터 페칭을 수행함으로써 클라이언트에서 불필요한 데이터 요청을 줄이고, 서버와 클라이언트 간의 트래픽을 최소화 가능. 이를 통해 네트워크 성능을 최적화.

 

일단, 결론을 말하자면 Tanstack query를 쓰면서 서버 컴포넌트로 만들 수는 없지만 서버에서 데이터를 받아와서

그걸 다시 useQuery를 거쳐 클라이언트 컴포넌트로 데이터를 넘겨 줄 수 있다.

 

확실히 그냥 Tanstack query만 쓸 때보다는 초기 데이터 페칭이 빠르다.

 

 

그럼 이제 그 방법을 정리해보겠다!

 

하이드레이션이라는 것을 사용하면된다.

하이드레이션(Hydration)은 SSR(Server-Side Rendering) 환경에서 클라이언트로 전송된 데이터를 클라이언트 측의 상태 관리 라이브러리에 다시 통합하는 과정이다.

 

TanStack Query는 React 애플리케이션에서 데이터 패칭과 캐싱을 손쉽게 구현할 수 있는 라이브러리로, 하이드레이션 기능을 지원한다.

 

 

하이드레이션 설정

  1. 서버 측에서 데이터 페칭 및 상태 저장
  2. 클라이언트 측에서 하이드레이션

 

서버 측 설정

// pages/_app.js
import { QueryClient, QueryClientProvider, Hydrate } from '@tanstack/react-query';
import { useState } from 'react';
import '../styles/globals.css';

function MyApp({ Component, pageProps }) {
  const [queryClient] = useState(() => new QueryClient());

  return (
    <QueryClientProvider client={queryClient}>
      <Hydrate state={pageProps.dehydratedState}>
        <Component {...pageProps} />
      </Hydrate>
    </QueryClientProvider>
  );
}

export default MyApp;

 

 

데이터 페칭 및 상태 저장

// pages/index.js
import { QueryClient, dehydrate, useQuery } from '@tanstack/react-query';
import fetchData from '../lib/fetchData';

export async function getServerSideProps() {
  const queryClient = new QueryClient();

  await queryClient.prefetchQuery(['dataKey'], fetchData);

  return {
    props: {
      dehydratedState: dehydrate(queryClient),
    },
  };
}

export default function Home() {
  const { data, error, isLoading } = useQuery(['dataKey'], fetchData);

  if (isLoading) return <div>Loading...</div>;
  if (error) return <div>Error: {error.message}</div>;

  return (
    <div>
      <h1>Fetched Data</h1>
      <pre>{JSON.stringify(data, null, 2)}</pre>
    </div>
  );
}

 

 

데이터 페칭 함수

// lib/fetchData.js
const fetchData = async () => {
  const res = await fetch('https://api.example.com/data');
  if (!res.ok) {
    throw new Error('Network response was not ok');
  }
  return res.json();
};

export default fetchData;

 

 

서버 측에서 데이터를 미리 가져와서(dehydrate) 클라이언트로 전달한 후,

클라이언트 측에서 하이드레이션을 통해 상태를 복원하는 방식이다.

이때 쿼리키는 이름이 동일 해야한다.

 

이를 통해 SSR과 클라이언트 측에서 일관된 상태를 유지 가능하다.