React Query의 QueryClientProvider 초기 설정

eee·2024년 12월 26일
1

React Query를 사용하는 첫 번째 단계는 queryClient를 생성하고 어플리케이션을 로 감싸는 것이다.

서버 렌더링을 할 때는 앱 내에서 리액트 상태에 queryClient 인스턴스를 생성하는 것이 중요하다. 이렇게 하면 데이터가 서로 다른 유저와 요청들 사이에 공유되지 않고, 컴포넌트 라이프사이클당 한 번만 queryClient가 생성된다.

기본 코드

// app/root.tsx
import { Outlet } from "@remix-run/react";
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
 
export default function MyApp() {
  const [queryClient] = React.useState(
    () =>
      new QueryClient({
        defaultOptions: {
          queries: {
			// With SSR, we usually want to set some default staleTime
            // above 0 to avoid refetching immediately on the client
            staleTime: 60 * 1000,
          },
        },
      })
  );
 
  return (
    <QueryClientProvider client={queryClient}>
      <Outlet />
    </QueryClientProvider>
  );
}

코드 설명

const [queryClient] = React.useState(
  () =>
    new QueryClient({
      defaultOptions: {
        queries: {
		  staleTime: 60 * 1000,
        },
      },
    })
);
  • QueryClient란?
    React Query에서 데이터를 캐싱하고 상태를 관리하는 객체

  • useState를 사용하는 이유

    • QueryClient를 리액트의 상태로 관리하여 컴포넌트 라이프사이클마다 한 번만 생성되도록 보장
    • 컴포넌트가 재렌더링 되더라도 동일한 QueryClient 인스턴스를 재사용할 수 있음
  • defaultOptions
    QueryClient를 초기화할 때의 기본 설정

    • staleTime: 데이터를 신선한 상태로 간주하는 시간(밀리초 단위)
      • 기본적으로 React Query는 데이터를 가져온 후 일정 시간이 지나면 데이터를 다시 요청
      • 여기서는 60초 동안 데이터를 신선한 상태로 간주하여, 그 시간 내에 재요청을 방지함
return (
  <QueryClientProvider client={queryClient}>
    <Outlet />
  </QueryClientProvider>
);
  • QueryClientProvider란?

    • React Query에서 제공하는 컨텍스트 프로바이더로, 애플리케이션 전체에 QueryClient를 전달
    • 하위 컴포넌트는 이 프로바이더를 통해 React Query의 훅(useQuery, useMutation 등)을 사용할 수 있음

서버와 브라우저 상황을 구분한 QueryProvider 코드

// In Next.js, this file would be called: app/providers.tsx
'use client'

// Since QueryClientProvider relies on useContext under the hood, we have to put 'use client' on top
import {
  isServer,
  QueryClient,
  QueryClientProvider,
} from '@tanstack/react-query'

function makeQueryClient() {
  return new QueryClient({
    defaultOptions: {
      queries: {
        // With SSR, we usually want to set some default staleTime
        // above 0 to avoid refetching immediately on the client
        staleTime: 60 * 1000,
      },
    },
  })
}

let browserQueryClient: QueryClient | undefined = undefined

function getQueryClient() {
  if (isServer) {
    // Server: always make a new query client
    return makeQueryClient()
  } else {
    // Browser: make a new query client if we don't already have one
    // This is very important, so we don't re-make a new client if React
    // suspends during the initial render. This may not be needed if we
    // have a suspense boundary BELOW the creation of the query client
    if (!browserQueryClient) browserQueryClient = makeQueryClient()
    return browserQueryClient
  }
}

export default function Providers({ children }: { children: React.ReactNode }) {
  // NOTE: Avoid useState when initializing the query client if you don't
  //       have a suspense boundary between this and the code that may
  //       suspend because React will throw away the client on the initial
  //       render if it suspends and there is no boundary
  const queryClient = getQueryClient()

  return (
    <QueryClientProvider client={queryClient}>{children}</QueryClientProvider>
  )
}

코드 설명

let browserQueryClient: QueryClient | undefined = undefined

function getQueryClient() {
  if (isServer) {
    return makeQueryClient()
  } else {
    if (!browserQueryClient) browserQueryClient = makeQueryClient()
    return browserQueryClient
  }
}

브라우저 환경에서 QueryClient를 한 번만 생성하여 재사용하기 위해 싱글톤 변수로 선언

서버 환경

  • isServer 값이 true인 경우, 항상 새로운 QueryClient 생성
    • 서버는 다수의 요청을 처리하므로, 요청 간 상태 공유를 방지하기 위해 매 요청마다 독립적인 QueryClient가 필요

브라우저 환경

  • isServer 값이 false인 경우, browserQueryClient 변수 확인
    • browserQueryClient가 없으면 새로 생성하고, 이미 있으면 기존 값 재사용
    • 브라우저 환경에서 QueryClient가 여러 번 생성되는 것을 방지할 수 있음

Suspense 문제 방지

  • React가 Suspense로 인해 렌더링을 중단하거나 다시 시도할 때 QueryClient가 재생성되면, 캐시 데이터와 상태가 초기화되고 동일한 데이터 요청이 중복 실행될 수 있음.
  • 브라우저 환경에서는 싱글톤 패턴으로 QueryClient를 관리(전역 변수로 관리)하여 렌더링 중단이 발생해도 동일한 인스턴스를 재사용하도록 함

[참고문서]

https://tanstack.com/query/v5/docs/framework/react/guides/ssr
https://tanstack.com/query/v5/docs/framework/react/guides/advanced-ssr

0개의 댓글