Next.JS에 리액트 쿼리 적용하기

윤뿔소·2023년 11월 5일
6

Next.JS

목록 보기
3/3
post-thumbnail

이번 글은 Next.JS 13.4버전 이상의 App Router에 리액트 쿼리를 적용하는 방법을 정리해보겠다.

설치

리액트 쿼리는 서드파티 라이브러리기 때문에 npm 설치를 먼저 해주자

# npm
npm i @tanstack/react-query
# pnpm
pnpm add @tanstack/react-query
# yarn
yarn add @tanstack/react-query

react-query 라이브러리 이름이 Tanstack으로 바뀌었기 때문에 @tanstack/react-query로 설치해야한다.

Next.JS에 적용하기

13.4 버전 App Router임을 감안해달라.

여러 방법이 있는데 나는 Provider 파일을 따로 만들어 거기에 client 및 쿼리 생성 함수를 작성해 Layout에 덮어 씌우는 방법을 보여주겠다.

ReactQueryProviders 만들기

<ReactQueryProviders>{children}</ReactQueryProviders>로 덮여씌워 쿼리를 제공해야하기 때문에 ReactQueryProviders 컴포넌트를 만들어야한다.

// /src/utils/react-query-provider.tsx
'use client';
import { QueryClientProvider, QueryClient } from '@tanstack/react-query';
import { ReactQueryDevtools } from '@tanstack/react-query-devtools';
import { useState } from 'react';

export default function ReactQueryProviders({
  children,
}: React.PropsWithChildren) {
  const [client] = useState(
    new QueryClient({
      defaultOptions: {
        queries: {
          refetchOnWindowFocus: false, // 윈도우가 다시 포커스되었을때 데이터를 refetch
          refetchOnMount: false, // 데이터가 stale 상태이면 컴포넌트가 마운트될 때 refetch
          retry: 1, // API 요청 실패시 재시도 하는 옵션 (설정값 만큼 재시도)
        },
      },
    }),
  );

  return (
    <QueryClientProvider client={client}>
      {children}
      <ReactQueryDevtools initialIsOpen={false} />
    </QueryClientProvider>
  );
}
  1. 'use client'를 추가.
    Next.JS App router는 기본적으로 서버 컴포넌트지만, 리액트쿼리는 QueryClientProvider를 비롯해 서버 컴포넌트에서는 작동하지 않음.

  2. useStatenew QueryClient 생성
    참조 동일성을 유지하고 React에서 예상대로 상태를 관리하는 데 도움돼 useState로 생성. 자세한 설명은 아래 참고 글에

  3. defaultOptions 설정
    서버 비용을 줄이기 위해 refetch 설정을 건들여줌

  4. 만든 queryClientQueryClientProvider 컴포넌트의 client에 넣어줌

  5. 만든 QueryClientProvider를 작성 후 children도 작성

  6. (선택) Devtool인 ReactQueryDevtools도 작성해줌

참고: 왜 queryClient 설정에 useState를?

useState를 활용하는 것은 React Query의 QueryClientProvider 설정에서 특별한 경우의 선택이라 할 수 있다. useState를 적용하면 참조 동일성을 유지하며, 또한 React Query와 React가 예상하는 상태 관리를 조절하고, 컴포넌트 렌더링과 상태 업데이트를 조절하기 위함이다.
이에 대한 몇 가지 이유는 다음과 같다.

  1. 초기 렌더링 중 설정: React Query는 초기 렌더링 동안에 QueryClient를 설정하고 사용하기 위한 상태를 필요로 한다.
    초기 렌더링 동안에만 실행되는 함수를 제공하면 Lazy 초기 상태(Lazy initial state)를 활용해 초기 렌더링 동안에만 QueryClient를 생성하고, 이후에는 참조 동일성을 유지한다. 이것은 초기 설정을 효율적으로 관리하는 방법 중 하나다.

  2. 동적 설정 관리: QueryClientProvider의 설정을 동적으로 변경해야 할 때, useState를 활용해 QueryClient를 상태로 관리하는 것이 유용하다.
    동적으로 설정을 변경하려면 상태를 업데이트하고 그 변경을 QueryClientProvider에 적용하면 된다.

  3. 컴포넌트 렌더링과 분리: QueryClientProvider의 설정을 컴포넌트 수명주기와 연관해서 관리하고자 할 때 useState를 사용할 수 있다.
    이렇게 하면 컴포넌트가 마운트되거나 언마운트될 때 설정을 업데이트하고 관리할 수 있다.

최적화와 관련해, React Query는 참조 동일성을 유지하게 하는 초기 설정을 처리하려 한다. 이렇게 하면 초기 설정을 최적화하고 상태를 효율적으로 관리할 수 있다. 또한, React Query는 렌더링 성능과 데이터 캐싱에 대한 다양한 최적화를 제공하므로, 이러한 최적화를 활용해 웹 애플리케이션의 성능을 향상시킬 수 있다.

루트 레이아웃에 적용하기

Next.JS App Router는 라우팅에 영향을 주는 파일 및 폴더가 있는데, 그 중 하나가 layout.tsx이다.

간단하게 얘기해서 layout.tsx는 도메인 주소에 영향을 주는 page.tsx 파일 및 그 하위 디렉토리 파일들에게 UI 및 설정에 영향을 줄 수 있는 파일이다. _app.tsx와 비슷한 기능을 가진 파일이다. 근데 각 디렉토리에 적용할 수 있는.

그래서 저렇게 덮여 쓰여지기 때문에 레이아웃 파일에 넣어줘야한다.

// src/app/layout.tsx
import '#/styles/globals.css';
import { Noto_Sans_KR } from 'next/font/google'; // 한글 NotoSans를 사용.
import ReactQueryProviders from '#/utils/react-query-provider';

// Noto Sans Korean
const notoSansKr = Noto_Sans_KR({
  subsets: ['latin'],
  weight: ['100', '300', '400', '500', '700', '900'],
});

export const metadata = {
  title: '',
  description: '',
};

export default function RootLayout({
  children,
}: {
  children: React.ReactNode;
}) {
  return (
    <html lang='ko-KR' className={notoSansKr.className}>
      <body className=''>
        <ReactQueryProviders>{children}</ReactQueryProviders>
      </body>
    </html>
  );
}

경로가 src/app/layout.tsx 임을 보아 루트 레이아웃 파일임에 틀림없다!
작성한 ReactQueryProviders 컴포넌트를 작성하여 적용하면 된다! 되게 되게 쉽다!


간단하게 적용하는 방법을 알아봤다. 다음에는 직접 사용하고, 무한스크롤도 적용하는 법도 글을 써보겠다.

마지막으로 얘기하자면 사실 리액트쿼리가 지금 서버 컴포넌트가 나온 시점에서 점점 힘을 잃어가고 있다. Fetch API도 Next.JS 내장 기능이 강화됐고, 또 SSR 전용 API Routes도 있기 때문에 사실 선택지가 많아진 셈인 것.

그래도 API 통신 전중후 커스텀 용이, 전역 상태 급 캐시 보관, 적극적 캐시 관리, devtools 등의 이점이 있어 선택할만 하다. 프로젝트 방향성 등을 고려해 골라보자.

내가 썼던 글 중 라이브러리 선택 시 고려 글을 보면 좋을 듯! ^^

profile
코뿔소처럼 저돌적으로

3개의 댓글

comment-user-thumbnail
2023년 11월 12일

이번에 면접 봤는데 기능에 대해 깊이 탐구하는 자세가 중요하다하던데 태연님한테 좀 배워야겠습니다...

답글 달기
comment-user-thumbnail
2023년 11월 12일

React Query를 즐겨 사용하는 편인데, QueryClient를 React state로 설정하는 부분은 미처 알지 못했던 것 같네요! 흥미롭게 잘 읽었습니다!

답글 달기
comment-user-thumbnail
2023년 11월 12일

코드를 작성할 때는 항상 고민하고 다양한 관점에서 접근하시는게 보여지네요 배우고 갑니다!

답글 달기