[FE] Tanstack Query - useQuery Refetch 방식 비교

seunghee.Rho·2025년 3월 15일

FE

목록 보기
6/26
post-thumbnail

💡 React Query라는 이름으로 시작했지만, v4부터 Vue, Svelte 등의 다른 프레임워크에서도 활용할 수 있도록 기능이 확장되며 TanStack Query로 변경되었다.

Tanstack Query

React 애플리케이션에서 데이터를 가져오고(fetch), 캐싱하고(cashe), 동기화(sync), 갱신(update)하는 것을 쉽게 만들어주는 라이브러리로 서버 상태(Server State) 관리를 간편하게 해줌

Tanstack Query의 주요기능

✔️ 데이터 패칭 및 캐싱 자동화
✔️ 백그라운드 데이터 동기화
✔️ 상태 기반 API 요청(로딩, 오류 처리 등)
✔️ 자동 리패칭(재시도, 리프레시 등)
✔️ 훅 기반 API(useQuery, useMutation 등)

여기서 오늘은 useQuery의 데이터 리패칭(Data Refetching)에 대해 알아보려고 한다.

useQuery

useQuery는 Tanstack Query의 핵심 훅 중 하나로, 데이터를 가져오고(fetching), 상태를 관리하는 역할이다.
Query는 데이터를 읽어오는 작업을, Mutation은 데이터를 변경하는 작업이라고 이해하면 쉽다.

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

const Users = () => {
  const { data, isLoading, error } = useQuery({
    queryKey: ["users"],
    queryFn: () => fetchUsers,
  });

  if (isLoading) return <p>Loading...</p>;
  if (error) return <p>Error!</p>;

  return <ul>{data.map(user => <li key={user.id}>{user.name}</li>)}</ul>;
};

export default Users;

➡️ useQuery를 사용하여 데이터를 가져옴.
➡️ queryKey: ["users"] 👉🏻 쿼리 캐시에서 데이터를 관리하는 고유한 키
➡️ queryFn: fetchUsers 👉🏻 데이터를 가져오는 비동기 함수
➡️ isLoading, error, data 값을 활용하여 로딩, 에러, 정상 데이터를 처리

refetch

refetch는 useQuery에서 데이터를 다시 불러올 수 있도록 하는 함수

기본적으로 useQuery는 자동으로 데이터를 패칭하지만, 특정 시점에서 수동으로 다시 요청하고 싶을 때 refetch()를 사용한다.

const { data, refetch } = useQuery({
  queryKey: ["users"],
  queryFn: fetchUsers,
});

<button onClick={() => refetch()}>🔄 Refresh Data</button>

➡️ 버튼을 클릭하면 fetchUsers()가 다시 실행되어 새로운 데이터를 가져옴
➡️ 기존 데이터를 유지하면서 새로운 데이터 패칭

위와 같은 기본적인 refetch 방식 외에도 다양한 방법이 있다.

데이터 갱신과 관련하여 invalidateQueries, refetchQueries, setQueryData가 있으며,
이 세 가지 기능이 어떻게 다르고, 언제 사용해야 하는지 자세히 알아보았다 🔍

1️⃣ invalidateQueries()

✔️ 쿼리 캐시를 무효화(Invalidate)하고, 필요할 때 자동으로 다시 패칭함

  • 기존의 캐시된 데이터를 무효화(invalidate)하고, React Query가 알아서 다시 패칭하도록 한다.
  • 자동으로 데이터를 다시 가져오지만, 즉시 실행되지는 않는다. 👉🏻 다음 렌더링에서 다시 패칭된다.

사용예시

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

const queryClient = useQueryClient();

const updateUserData = async () => {
  await fetch("/api/updateUser", { method: "POST" });
  
  // 기존 캐시된 "user" 데이터를 무효화 → React Query가 자동으로 다시 패칭
  queryClient.invalidateQueries({ queryKey: ["user"] });
};

➡️ 즉시 API 요청을 보내지 않고, 다음 렌더링에서 데이터를 다시 가져옴
➡️ 기존 캐시를 무효화하고, 필요할 때 새로 데이터를 가져오도록 유도
❌ 즉시 실행되지 않기 때문에 변경된 데이터가 늦게 반영될 수도 있음

💡 데이터 변경 후 최신 데이터 유지가 필요할 때 유용
💡 useMutation과 함께 사용하면 좋음

2️⃣ refetchQueries()

✔️ 즉시 API를 호출하여 데이터를 새로 가져옴 (invalidate 없이 바로 API 요청을 보냄)

  • invalidateQueries()와 비슷하지만 즉시 데이터를 다시 요청함.
  • 특정 쿼리 키를 지정하여 해당 데이터만 새로고침 가능
import { useQueryClient } from "@tanstack/react-query";

const queryClient = useQueryClient();

const refreshUserData = async () => {
  await queryClient.refetchQueries({ queryKey: ["user"] }); // 즉시 API 재요청
};

➡️ 시 API를 다시 호출하여 최신 데이터를 가져옴
➡️ 즉각적인 UI 업데이트가 필요할 때 유용
❌ 불필요한 API 요청이 많아질 가능성이 있음

💡 사용자가 버튼을 눌러 최신 데이터를 보고 싶을 때 유용

3️⃣ setQueryData()

✔️ API 호출 없이 캐시된 데이터를 직접 수정

  • invalidateQueries()나 refetchQueries()는 API를 다시 호출하지만, setQueryData는 API 호출 없이 로컬 캐시 데이터를 직접 변경함.
  • 성능 최적화가 필요한 경우 유용
import { useQueryClient } from "@tanstack/react-query";

const queryClient = useQueryClient();

const updateUserBalance = () => {
  queryClient.setQueryData(["user"], (oldData) => ({
    ...oldData,
    balance: oldData.balance + 100, // 기존 데이터에 100 추가
  }));
};

➡️ API 요청 없이 즉시 UI 업데이트 가능
➡️ 불필요한 네트워크 요청을 줄일 수 있음
❌ 실제 서버 데이터와 다를 가능성이 있음

결론

✅ invalidateQueries() → 캐시를 무효화하여 자동으로 데이터를 다시 가져오게 함 (즉시 실행되지 않음).
✅ refetchQueries() → 특정 데이터를 즉시 다시 가져옴
✅ setQueryData() → API 요청 없이 로컬 캐시 데이터를 직접 변경하여 성능을 최적화

🚀 상황에 맞게 적절한 기능을 선택하여 성능을 최적화하는 것이 좋을 것 같다.

Tanstack Query : https://tanstack.com/query/latest

profile
Web Developer

0개의 댓글