본문 바로가기

개발 공부/React

Next.js에서 레이아웃 구성 (2) / QueryProvider

코드 출처 : https://github.com/Cluster-Taek/next14-boilerplate

 

GitHub - Cluster-Taek/next14-boilerplate

Contribute to Cluster-Taek/next14-boilerplate development by creating an account on GitHub.

github.com

 

 

import AuthProvider from './auth-provider';
import ModalProvider from './modal-provider';
import { QueryProvider } from './query-provider';
import SessionProvider from '@/contexts/session-provider';

interface ICoreProviderProps {
  children?: React.ReactNode;
}

const CoreProvider = ({ children }: ICoreProviderProps) => {
  return (
    <SessionProvider>
      <AuthProvider>
        <QueryProvider>
          <ModalProvider>{children}</ModalProvider>
        </QueryProvider>
      </AuthProvider>
    </SessionProvider>
  );
};

export default CoreProvider;

 

QueryProvider

'use client';

import { fetchApi } from '@/lib/base';
import { getClearObject } from '@/utils/utils';
import { QueryClient, QueryClientProvider, keepPreviousData } from '@tanstack/react-query';
import { ReactQueryDevtools } from '@tanstack/react-query-devtools';
import { useState } from 'react';

export const QueryProvider = ({ children }: { children: React.ReactNode }) => {
  const fetcher = async (url: string, params?: Record<string, unknown>) => {
    return fetchApi.get(url, params);
  };

  const [queryClient] = useState(
    () =>
      new QueryClient({
        defaultOptions: {
          queries: {
            retry: false,
            staleTime: 1000 * 60,
            gcTime: 1000 * 60 * 5,
            queryFn: ({ queryKey }) =>
              fetcher(queryKey[0] as string, queryKey[1] ? getClearObject(queryKey[1]) : undefined),
            placeholderData: keepPreviousData,
          },
        },
      })
  );

  return (
    <QueryClientProvider client={queryClient}>
      <ReactQueryDevtools />
      {children}
    </QueryClientProvider>
  );
};
  • React Query를 활용하여 데이터 fetching과 캐싱 로직을 제공하는 QueryProvider 컴포넌트를 정의합니다.
  • 이 QueryProvider는 애플리케이션 내에서 @tanstack/react-query의 기능을 쉽게 사용할 수 있도록 설정합니다.
  • fetchApi: 데이터를 가져오는 커스텀 함수. GET 요청을 처리하며, URL과 매개변수를 받아 서버로 요청을 보냅니다.
  • getClearObject: 주어진 객체를 정리(clean)하는 유틸리티 함수. 쿼리 매개변수를 처리할 때 사용됩니다.
  • QueryClient & QueryClientProvider: React Query에서 데이터를 캐싱하고 쿼리 관련 옵션을 설정하는 데 사용됩니다.
  • ReactQueryDevtools: React Query 개발 도구로, 쿼리 상태를 디버깅할 수 있습니다.
  • useState: React의 상태 관리 훅으로, QueryClient의 인스턴스를 생성하고 유지합니다.

주요 기능 및 동작

  1. 데이터 Fetching 및 캐싱:
    • fetcher를 통해 API 호출.
    • 쿼리 키(queryKey)를 기반으로 데이터를 캐싱.
  2. 캐싱 정책:
    • staleTime과 gcTime을 통해 데이터의 유효 기간과 삭제 시점을 설정.
    • keepPreviousData를 사용해 새 데이터를 로드하는 동안 이전 데이터를 유지.
  3. 개발 도구:
    • ReactQueryDevtools로 현재 쿼리 상태를 시각적으로 확인.
  4. 성능 최적화:
    • QueryClient 인스턴스를 React의 상태로 관리하여 불필요한 초기화를 방지.

 

데이터 Fetching 함수

const fetcher = async (url: string, params?: Record<string, unknown>) => {
  return fetchApi.get(url, params);
};

 

  • fetcher 함수는 fetchApi.get을 사용해 데이터를 가져옵니다.
  • url: 요청할 API의 URL.
  • params: 선택적인 쿼리 매개변수. 객체 형태로 전달됩니다

 

QueryClient 인스턴스 생성

const [queryClient] = useState(
  () =>
    new QueryClient({
      defaultOptions: {
        queries: {
          retry: false,
          staleTime: 1000 * 60, // 1분 동안 데이터를 신선한 상태로 유지
          gcTime: 1000 * 60 * 5, // 5분 후 가비지 컬렉션
          queryFn: ({ queryKey }) =>
            fetcher(queryKey[0] as string, queryKey[1] ? getClearObject(queryKey[1]) : undefined),
          placeholderData: keepPreviousData, // 이전 데이터 유지
        },
      },
    })
);

 

 

  • useState:
    • QueryClient를 초기화하고 React의 상태로 관리.
    • 상태로 관리함으로써 컴포넌트가 리렌더링될 때마다 새로운 QueryClient가 생성되지 않도록 보장.
  • defaultOptions:
    • React Query의 기본 쿼리 옵션을 설정:
      • retry: 실패한 요청에 대해 재시도를 하지 않음.
      • staleTime: 데이터가 신선하다고 간주되는 기간. (여기서는 1분)
      • gcTime: 캐시된 데이터를 5분 후에 가비지 컬렉션.
      • queryFn: 기본 쿼리 함수로 fetcher 사용.
      • placeholderData: 새 데이터를 로드하는 동안 이전 데이터를 유지.

 

컴포넌트 렌더링

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

 

 

  • QueryClientProvider:
    • React Query의 컨텍스트를 제공하며, 모든 자식 컴포넌트에서 쿼리 관련 기능을 사용할 수 있게 함.
    • client로 생성한 queryClient 인스턴스를 전달.
  • ReactQueryDevtools:
    • 개발 도구를 활성화. 개발 환경에서 쿼리 상태를 확인하고 디버깅할 수 있음.
  • children:
    • QueryProvider의 자식 요소로 렌더링되며, 이들 컴포넌트에서 React Query를 사용할 수 있음.

 

장점

  • React Query의 강력한 기능: 데이터 fetching, 캐싱, 상태 관리 간소화.
  • 중앙화된 설정: QueryProvider를 통해 쿼리 정책을 전역에서 일관되게 관리.
  • 유연성: 필요에 따라 개별 쿼리의 옵션을 커스터마이징 가능.