
💡 React Query라는 이름으로 시작했지만, v4부터 Vue, Svelte 등의 다른 프레임워크에서도 활용할 수 있도록 기능이 확장되며 TanStack Query로 변경되었다.
React 애플리케이션에서 데이터를 가져오고(fetch), 캐싱하고(cashe), 동기화(sync), 갱신(update)하는 것을 쉽게 만들어주는 라이브러리로 서버 상태(Server State) 관리를 간편하게 해줌
✔️ 데이터 패칭 및 캐싱 자동화
✔️ 백그라운드 데이터 동기화
✔️ 상태 기반 API 요청(로딩, 오류 처리 등)
✔️ 자동 리패칭(재시도, 리프레시 등)
✔️ 훅 기반 API(useQuery, useMutation 등)
여기서 오늘은 useQuery의 데이터 리패칭(Data Refetching)에 대해 알아보려고 한다.
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는 useQuery에서 데이터를 다시 불러올 수 있도록 하는 함수
기본적으로 useQuery는 자동으로 데이터를 패칭하지만, 특정 시점에서 수동으로 다시 요청하고 싶을 때 refetch()를 사용한다.
const { data, refetch } = useQuery({
queryKey: ["users"],
queryFn: fetchUsers,
});
<button onClick={() => refetch()}>🔄 Refresh Data</button>
➡️ 버튼을 클릭하면 fetchUsers()가 다시 실행되어 새로운 데이터를 가져옴
➡️ 기존 데이터를 유지하면서 새로운 데이터 패칭
위와 같은 기본적인 refetch 방식 외에도 다양한 방법이 있다.
데이터 갱신과 관련하여 invalidateQueries, refetchQueries, setQueryData가 있으며,
이 세 가지 기능이 어떻게 다르고, 언제 사용해야 하는지 자세히 알아보았다 🔍
✔️ 쿼리 캐시를 무효화(Invalidate)하고, 필요할 때 자동으로 다시 패칭함
사용예시
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과 함께 사용하면 좋음
✔️ 즉시 API를 호출하여 데이터를 새로 가져옴 (invalidate 없이 바로 API 요청을 보냄)
import { useQueryClient } from "@tanstack/react-query";
const queryClient = useQueryClient();
const refreshUserData = async () => {
await queryClient.refetchQueries({ queryKey: ["user"] }); // 즉시 API 재요청
};
➡️ 시 API를 다시 호출하여 최신 데이터를 가져옴
➡️ 즉각적인 UI 업데이트가 필요할 때 유용
❌ 불필요한 API 요청이 많아질 가능성이 있음
💡 사용자가 버튼을 눌러 최신 데이터를 보고 싶을 때 유용
✔️ 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