React-Query (TanStack Query)

송윤서·2025년 3월 20일

Next.js

목록 보기
5/7
post-thumbnail

리액트 쿼리는 프론트엔드 개발을 하면서 들어본 적은 있었지만, 제대로 다뤄본 적은 없었습니다. 그러다 최근 수업 시간에 처음으로 접하게 되었고, 이번 기회를 통해 리액트 쿼리에 대해 더 깊이 알아보고자 했습니다.
그러면 알아봅시다요를레히 🔥

React-Query (TanStack Query)는 무엇인가

fetching, caching, 서버 데이터와의 동기화를 지원해주는 라이브러리

-> 웹 어플리케이션에서 서버 state를 손쉽게 페칭하고 캐싱해주며, 이를 동기적으로 업데이트할 수 있게 해줍니다.

이걸 왜 사용하는 걸까?

기존 방식은 매번 fetch할 때마다 로딩, 에러, 데이터 상태를 직접 관리해야 해서 코드가 복잡해지고, store에 서버 데이터와 클라이언트 데이터를 함께 담으면 상태가 꼬여 예측이 어려워지는 문제가 있었습니다. 또한 데이터 수정 후에는 직접 갱신 처리를 해줘야 하고, 캐싱이 없어 동일한 요청을 반복하게 되는 비효율도 존재합니다.

이러한 문제를 해결하기 위해 React Query를 사용하는 이유를 3가지 알아보자!!

  1. 서버 상태 관리 자동화
    로딩, 에러, 성공 상태를 자동으로 관리해주기 때문에 useState, useEffect로 일일이 처리할 필요가 없습니다.
  2. 자동 캐싱과 데이터 동기화
    같은 데이터를 여러 곳에서 사용해도 중복 요청 없이 캐시를 활용하며, 필요한 시점에 자동으로 refetch가 이루어집니다.
  3. 코드 간결화 & 유지보수 용이
    비동기 로직이 깔끔하게 정리되어 코드가 훨씬 간결해지고, 가독성과 유지보수성도 향상됩니다.

주요 기능

  • 데이터 가져오기 및 캐싱
  • 동일 요청의 중복 제거
  • 신선한 데이터 유지
  • 무한 스크롤, 페이지네이션 등의 성능 최적화
  • 네트워크 재연결, 요청 실패 등의 자동 갱신

데이터 캐싱

TanStack Query를 활용해서 데이터를 가져올 때는 항상 쿼리 키(queryKey)를 지정하게 됩니다. 이 쿼리 키는 캐시된 데이터와 비교해 새로운 데이터를 가져올지, 캐시된 데이터를 사용할지 결정하는 기준이 됩니다.

// 예시 코드
import { useQuery } from '@tanstack/react-query';

const { data } = useQuery(['user'], () =>
  fetch('https://jsonplaceholder.typicode.com/users/1').then(res => res.json())
);

useQuery

서버에서 데이터를 불러오고, 캐싱하고, 로딩/에러 상태를 관리해주는 핵심 훅
즉, 서버로부터 데이터를 요청하여 받아오는 GET api

보통 API 요청을 직접 useEffect + useState 조합으로 처리하던 방식을 대체하고 코드를 더 간결하고 안정적으로 만들어준다.

// 사용법
const {data} = useQuery(쿼리 키, 쿼리 함수, 옵션);
// 예시
const { data, isLoading, isPending, isFetching, refetch } = useQuery({
    queryKey: ["about"],
    queryFn: () =>
      fetch("https://jsonplaceholder.typicode.com/posts")
        .then((res) => res.json())
        .then((res: { id: number; title: string; body: string }[]) =>
          _.shuffle(res)
        ),
  });

Query Key

React Query에서 제공하는 hooks인 useQuery와 useMutation을 사용하면 해당 hooks의 queryKey를 지정

특징 및 역할

  1. React Query에서는 query keys를 기반으로 해서 쿼리 캐싱 관리
  2. query key는 문자열, 문자열의 배열 혹은 중첩된 객체(nested object)로 지정 가능
  3. query keys는 query data에 고유하고 직렬화하여 사용

기본 작성 규칙

  1. 배열로 작성되는 queryKey의 값은 string key를 먼저 작성한다.
  2. string key는 여러 개를 지정할 수 있지만 key가 연관되는 data는 고유하다.
  3. query에 필요한 추가 정보는 string key 뒤에 작성한다.

Query Function

useQuery를 통해서 쿼리를 정의할 때 전달하는 함수입니다.
비동기 익명 함수, 정의해둔 함수를 전달할 수 있습니다.

option

쿼리에 사용되는 옵션 종류

반환 객체 종류

useMutation

PUT, UPDATE, DELETE 와 같이 값을 변경할 때 사용하는 API다.
반환값은 useQuery와 동일하다!

사용법

// 첫 번째 방법
const deleteData = useMutation(() => axios.delete(`api/delete/${id}`));

// 두 번째 방법
const deleteData = useMutation({
  mutationFn: (id) => axios.delete(`api/delete/${id}`)
})

이제 개념을 알았으니 직접 해보자!

설치하기

npm add @tanstack/react-query
npm add @tanstack/react-query-devtools

리액트쿼리 세팅

react Query를 Next.js 앱에서 전역으로 사용할 수 있도록 세팅

// App > providers.tsx -> React Query 전역 설정
"use client";

import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
import React, { PropsWithChildren, useState } from "react";

type Props = {} & PropsWithChildren;

const Providers = ({ children }: Props) => {
  const [queryclient] = useState(() => new QueryClient());
  return (
    <QueryClientProvider client={queryclient}>{children}</QueryClientProvider>
  );
};

export default Providers;
// app > layout.tsx -> 앱 전체를 Provider로 감쌈
<Providers>{children}</Providers>
// app > middleware.tsx -> 요청을 그대로 통과시킴 (기본 설정)
export function middleware(request: NextRequest) {
  return NextResponse.next();
}

적용

React Query로 불러온 데이터를 가져와서 보여주는 페이지

// app > about > page.tsx
"use client";

import { useQuery } from "@tanstack/react-query";
import React from "react";

const AboutPage = () => {
  const { data, isLoading } = useQuery({
    queryKey: ["about"],
    queryFn: () =>
      fetch("https://jsonplaceholder.typicode.com/posts").then((res) =>
        res.json()
      ),
  });
  if (isLoading) return <div>Loading...</div>;
  return (
    <ul className="p-4 flex flex-col gap-2">
      {data?.map((item: { id: number; title: string; body: string }) => (
        <li key={item.id} className="border rounded p-4 flex flex-col gap-2">
          <h1 className="text-2xl font-bold">{item.title}</h1>
          <p className="text-sm">{item.body}</p>
        </li>
      ))}
    </ul>
  );
};

export default AboutPage;

결과


마무리

처음에는 다소 생소하게 느껴졌지만, 직접 사용해보며 React Query가 널리 활용되는 이유를 체감할 수 있었습니다. 비동기 데이터 처리 과정이 훨씬 간결하고 체계적으로 개선되었으며, 코드의 가독성과 유지보수 측면에서도 큰 강점을 느꼈습니다.이번 경험을 통해 서버 상태 관리를 보다 효율적으로 접근할 수 있는 새로운 관점을 얻게 되었고, 앞으로 관련 작업에 있어 React Query를 적극 활용하고자 합니다.

profile
Front-end Developer

0개의 댓글