Next.js 14 app router + React-Query v5


무한스크롤과 optimistic update를 구현하기 위해 next.js에 react-query를 사용하기로 했다.

next.js 14 app router에 react-query를 설정하는 방법을 기록하자

1. Provider 생성

  1. 프로젝트 root 경로에 providers 폴더 생성
  2. ReactQueryProvider.tsx 생성
1'use client';
2
3import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
4import { ReactQueryDevtools } from '@tanstack/react-query-devtools';
5import { useState } from 'react';
6
7function ReactQueryProvider({ children }: React.PropsWithChildren) {
8  const [client] = useState(new QueryClient());
9
10  return (
11    <QueryClientProvider client={client}>
12      {children}
13      <ReactQueryDevtools initialIsOpen={false} />
14    </QueryClientProvider>
15  );
16}
17
18export default ReactQueryProvider;

new QueryClient() 인스턴스를 state로 선언하는 이유

  • useState를 사용하여 QueryClient 인스턴스를 생성하면, 컴포넌트가 다시 렌더링되더라도 동일한 QueryClient 인스턴스가 유지된다.
  • 만약 useState를 사용하지 않고 단순히 const client = new QueryClient()를 사용하면, 컴포넌트가 리렌더링될 때마다 새로운 QueryClient 인스턴스가 생성된다. 이는 불필요한 인스턴스 생성과 데이터 캐싱의 중복을 초래한다.
  • ReactQueryDevtools 는 개발 모드일 때 여러 쿼리를 시각적으로 볼 수 있는 관리 툴이다.

2. 최상위 layout.tsx 에서 children 감싸기

1import ReactQueryProvider from '../providers/ReactQueryProvider';
2import './globals.css';
3
4export default function RootLayout({
5  children,
6}: Readonly<{
7  children: React.ReactNode;
8}>) {
9  return (
10    <html lang='ko'>
11      <body>
12        <ReactQueryProvider>{children}</ReactQueryProvider>
13      </body>
14    </html>
15  );
16}

최상위 레이아웃에서 ReactQueryProvider 로 감싸주는 이유

  • 모든 컴포넌트가 React-Query의 컨텍스트에 접근할 수 있다.
    이를 통해 모든 페이지와 컴포넌트가 동일한 QueryClient 인스턴스를 공유하고, 새로운 페이지나 컴포넌트를 추가할 때마다 개별적으로 QueryClientProvider를 설정할 필요가 없다.

3. 컴포넌트에서 useQuery 사용하기

1const { data, isLoading } = useQuery<Reply[]>({
2    queryKey: ['reply-list', post_id],
3    queryFn: () => getReplyList(post_id),
4  });

끝!