
const { data: groupData, isLoading, error } = useQuery({
queryKey: ['group', groupId],
queryFn: () =>
groupId
? getGroup({ id: groupId })
: Promise.reject(new Error('No ID provided')),
enabled: !!groupId,
staleTime: 0,
refetchOnMount: 'always',
});
queryKey를 사용하므로 같은 데이터를 여러 곳에서 요청해도 한 번만 API 요청을 실행합니다.useEffect + fetch)은 컴포넌트가 마운트될 때마다 API 요청을 실행하여 불필요한 네트워크 요청이 발생했지만, useQuery는 이를 방지합니다.useQuery는 invalidateQueries(['group', groupId])을 통해 데이터 변경 시 자동으로 최신 상태로 갱신됩니다.isLoading, error 상태가 내장되어 있어, 별도로 useState를 추가하지 않아도 됩니다.if (isLoading) return <Loading />;을 통해 간단하게 처리할 수 있습니다.export default function HeaderTeam({ type, onClick }: HeaderTeamProps) {
const {
data: userData,
isLoading,
error,
} = useQuery<GetUserResponse>({
queryKey: ['user'],
queryFn: getUser,
staleTime: 5 * 60 * 1000,
});
if (isLoading) {
return <div className="hidden tablet:block">로딩 중...</div>;
}
if (error) {
return <div>유저 데이터를 불러오는데 실패했습니다.</div>;
}
}
→ 불필요한 API 호출을 줄이고, 데이터가 변경될 때마다 자동으로 UI가 최신화됩니다.
→ 로딩/에러 상태를 자동으로 관리할 수 있어 코드가 더 간결해집니다.
const queryClient = useQueryClient();
const createMutation = useMutation({
mutationFn: (newTaskList: { name: string }) => {
const trimmedName = newTaskList.name.trim();
return createTaskList({ groupId, name: trimmedName });
},
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: ['taskLists', groupId] });
queryClient.invalidateQueries({ queryKey: ['group', groupId] });
methods.reset();
closeModal();
},
});
invalidateQueries(['taskLists', groupId])을 사용하면 새로운 데이터를 다시 불러와도 기존 캐싱된 데이터와 병합하여 최소한의 업데이트만 실행합니다.invalidateQueries를 사용하면 변경된 데이터를 즉시 서버에서 가져와 동기화하기 때문에 UI가 항상 최신 상태로 유지됩니다.→ 같은 데이터를 여러 곳에서 공유하여 중복 API 요청을 방지할 수 있습니다.
→ 변경된 데이터를 자동으로 최신화하여 페이지를 새로고침하지 않아도 반영됩니다.
→ 네트워크 부하를 줄이고, 사용자 경험(UX)을 개선할 수 있습니다.