← 글 목록

notes

Nextjs in React Query

Next.js에서 React Query를 연결하는 데이터 패칭·캐시 구성 메모.

  • 서버에서 온 데이터는 클라이언트 상태랑 따로 다룬다
  • 캐시를 먼저 보여 주고 오래됐으면 뒤에서 다시 받는다
  • App Router 에서는 서버 컴포넌트에서 미리 채운 캐시를 넘겨 받는다

React Query 는

React Query(지금 이름은 TanStack Query) 는 서버 상태를 불러오고, 캐시하고, 동기화하는 일을 대신 해 주는 라이브러리다.

React 나 Next.js 같은 프레임워크는 데이터를 어떻게 가져오고 갱신할지 정해 주지 않는다. Redux 같은 기존 상태 관리 라이브러리는 클라이언트 상태에는 잘 맞는데 서버 상태에는 잘 안 맞는다. 서버 상태는 내 앱이 아니라 서버가 주인이고, 다른 사람이 언제든 바꿀 수 있어서다.

React Query 는 이 서버 상태를 알아서 갱신하고 맞춰 준다. 응답이 빨라지고, 클라이언트가 들고 있던 상태값도 크게 줄어든다.

스크린을 사용 했을 때 상태와 스크린을 사용하지 않았을때 캐시상태

캐시가 도는 방식

내가 생각하는 react-query 의 제일 강한 부분은 위 그림의 캐시다. 같은 queryKey 로 다시 요청하면 캐시에 있는 값을 바로 보여 주고, 값이 오래됐으면(stale) 뒤에서 조용히 다시 받아 바꾼다.

데이터를 추가하거나 지운 다음에는 invalidateQueries 로 해당 키 캐시를 무효화해서 새로 받게 한다. 무한 스크롤은 useInfiniteQuery 가 페이지 단위 캐시를 알아서 이어 붙인다. 클라이언트에서 데이터를 직접 들고 있을 필요가 없어지니 코드도 부하도 줄어든다.

기본값도 알아 두면 좋다. staleTime 은 0 이라 받자마자 stale 이고, 안 쓰는 캐시는 gcTime 기본 5분 뒤에 지워진다. v4 까지는 gcTime 이름이 cacheTime 이었다.

Next.js App Router 에서

App Router 에서는 서버 컴포넌트에서 데이터를 미리 받아 캐시를 채우고, dehydrate 로 직렬화해서 HydrationBoundary 로 넘긴다. 클라이언트의 useQuery 는 같은 키가 이미 캐시에 있어서 요청 없이 바로 그린다. 미리 받는 함수는 예전에 prefetchQuery 를 썼는데 지금 v5 문서는 queryClient.query 를 쓴다.

App Router 연결 예제
// app/providers.tsx
'use client'
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
import { useState } from 'react'

export default function Providers({ children }: { children: React.ReactNode }) {
  const [queryClient] = useState(() => new QueryClient({
    defaultOptions: { queries: { staleTime: 60 * 1000 } },
  }))
  return <QueryClientProvider client={queryClient}>{children}</QueryClientProvider>
}

// app/posts/page.tsx (서버 컴포넌트)
import { dehydrate, HydrationBoundary, QueryClient } from '@tanstack/react-query'

export default async function PostsPage() {
  const queryClient = new QueryClient()
  await queryClient.query({ queryKey: ['posts'], queryFn: getPosts })

  return (
    <HydrationBoundary state={dehydrate(queryClient)}>
      <Posts />
    </HydrationBoundary>
  )
}

서버 렌더링을 쓸 때는 staleTime 을 0 보다 크게 잡아 두는 게 좋다. 0 이면 클라이언트에서 받자마자 바로 다시 요청한다.