HTTP 요청을 전송하고 프론트엔드 UI와 백엔드 데이터가 동기화된 상태로 유지하는데 이용하는 라이브러리이다.
❗️반드시 필요한 것이 아니라 useEffect / fetch 를 사용하여도 된다.
하지만 Tanstack Query를 사용하면 더 쉽고 간단하게 프로젝트가 가능하다.
useEffect 사용코드가 길어지고, HTTP 요청을 받을 때마다 모든 컴포넌트에서 이렇게 작성해야 한다.
이때 useHTTP라는 커스텀 훅을 만들어 이 코드를 전부 넣은 후 재사용을 할 수 있다.
하지만,
다른 사이트에 갔다가 왔을 때 데이터가 업데이트된 경우, 변경된 데이터를 가져와 UI를 업데이트 하려고 할 때.
가져온 데이터를 캐시처리하고 메모리에 저장해서, 필요할 때 다시 사용하려고 할 때
➡️ 이러한 기능들을 넣으려고 할 때 직접 커스텀하기는 어려우므로 Tanstack 쿼리가 제공하는 고급 기능을 통해 적용할 수 있다.
useEffect(() => {
async function fetchEvents() {
setIsLoading(true);
const response = await fetch('http://localhost:3000/events');
if (!response.ok) {
const error = new Error('An error occurred while fetching the events');
error.code = response.status;
error.info = await response.json();
throw error;
}
const { events } = await response.json();
return events;
}
fetchEvents()
.then((events) => {
setData(events);
})
.catch((error) => {
setError(error);
})
.finally(() => {
setIsLoading(false);
});
}, []);
Tanstack Query 사용백엔드 데이터를 수정했을 때 사이트에서 바로 반영이 된다.
const { data, isPending, isError, error, refetch } = useQuery({
queryKey: ["events"],
queryFn: fetchEvents
});
npm install @tanstack/react-query
import { useQuery } from "@tanstack/react-query"
QueryClient 객체 생성import { QueryClient } from "@tanstack/react-query";
const queryClient = new QueryClient();
QueryClientProvider 로 감싸기import { QueryClientProvider } from "@tanstack/react-query";
function App() {
return (
<QueryClientProvider client={queryClient}>
<RouterProvider router={router} />
</QueryClientProvider>
);
}
이 훅을 사용하면, 원하는 데이터 정보, 로딩 상태 정보, 오류 정보를 알 수 있다.
객체를 전달하며, promise 를 반환하므로 원하는 값을 구조 분해 할당으로 빼올 수 있다.
ex) data, isPending, isError, error, refetch 등
queryKey : 쿼리를 식별하는 고유한 값으로, 배열 형태로 지정한다.
queryFn : 실제 요청을 전송할 때 실행할 코드
직접 HTTP 요청 코드를 작성해야 한다.
staleTime
TanStack Query는 캐시한 데이터를 신선(Fresh)하거나 상한(Stale) 상태로 구분해 관리한다.
즉, 캐시된 데이터가 신선하다면 캐시된 데이터를 사용하고, 만약 데이터가 상했다면 서버에 다시 요청해 신선한 데이터를 가져온다.
staleTime 옵션으로 지정할 수 있다.0 으로 상한 상태이므로, 다른 페이지에 갔다오면 데이터를 다시 받아오는 것이 기본인 것이다.isStale 로 확인할 수 있다.gcTime - 캐시된 데이터를 언제 버릴지 (garbage Collection) 시간 설정
gcTime이 경과하면 데이터를 삭제한다.gcTime이 경과하기 전까지는 캐시된 데이터를 재사용할 수 있다.1000 * 60 * 5) 이다.enabled - 쿼리가 실행될지 여부를 제어한다.
false : 실행 x true : 실행 oimport { useQuery } from '@tanstack/react-query'
export default function DelayedData() {
const { data } = useQuery({
queryKey: ['delay'],
queryFn: async () => (await fetch('https://api.primav.dev/v0/delay?t=1000')).json()
})
enabled: searchTerm !== undefined
return <div>{JSON.stringify(data)}</div>
}
true falsetrue로 설정true| 상태 | isLoading | isPending |
|---|---|---|
| 의미 | 첫 번째 쿼리 로딩 상태 | 쿼리가 진행 중일 때 (로딩/리패칭) |
| 언제 true? | 컴포넌트 렌더링 시 처음 쿼리가 실행될 때 | 쿼리가 로딩 중이거나 재요청 중일 때 |
| 주요 용도 | 처음 데이터를 요청할 때 로딩 상태를 표시 | 데이터가 로딩되거나 새로고침/리패칭 중일 때 표시 |
| 해제 시점 | 쿼리가 완료되면 false로 변경 | 쿼리가 완료되면 false로 변경 |
데이터를 수정할 때 사용한다. (write)
useQuery와 달리, useMutation은 자동으로 실행되지 않으며, 주로 이벤트 핸들러나 특정 조건에 의해 명시적으로 호출될 때 실행된다.
mutationKey - 지정할 수는 있지만 필요 없음
mutationFn - 실행할 함수
실제 데이터 변경 작업을 처리하며, mutate 호출 시 인자로 전달된 데이터를 처리한다.
mutate - 요청을 언제 실행할 것인지 지정해주는 함수
호출 시에 비동기 작업을 실행한다.
import { useMutation } from '@tanstack/react-query';
const createNewEvent = async ({ event }) => {
// API 호출 또는 데이터 처리
const response = await fetch('/api/events', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(event),
});
if (!response.ok) {
throw new Error('Event creation failed');
}
return response.json();
};
function EventForm() {
const { mutate, isLoading, isError, error } = useMutation({
mutationFn: createNewEvent,
});
const handleSubmit = (formData) => {
mutate({ event: formData });
};
return (
<div>
<form onSubmit={(e) => {
e.preventDefault();
const formData = { name: 'New Event', date: '2025-01-01' }; // 예시 데이터
handleSubmit(formData);
}}>
<button type="submit" disabled={isLoading}>Create Event</button>
</form>
{isError && <p>Error: {error.message}</p>}
{isLoading && <p>Loading...</p>}
</div>
);
}
참고 링크 - 이해가 안되는 부분에서 도움을 많이 받음