useQuery 사용하기
npm install @tanstack/react-query
yarn add @tanstack/react-query
먼저 TanStack Query 사용을 위해 설치를 해준다.
강의를 따라가면서 기존 코드에서 useQuery를 도입해보자.
NewEventsSection이라는 컴포넌트에는 커스텀 상태 관리와 useEffect hook이 있다.
컴포넌트가 마운트 될 때마다 fetchEvents라는 함수가 실행된다.
이 함수가 실행되면서 setIsLoading(true)가 되고, response 또는 error를 받아 그에 맞는 content를 보여준다.
export default function NewEventsSection() {
const [data, setData] = useState();
const [error, setError] = useState();
const [isLoading, setIsLoading] = useState(false);
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);
});
}, []);
let content;
if (isLoading) {
content = <LoadingIndicator />;
}
if (error) {
content = (
<ErrorBlock title="An error occurred" message="Failed to fetch events" />
);
}
if (data) {
content = (
<ul className="events-list">
{data.map((event) => (
<li key={event.id}>
<EventItem event={event} />
</li>
))}
</ul>
);
}
return (
<section className="content-section" id="new-events-section">
<header>
<h2>Recently added events</h2>
</header>
{content}
</section>
);
}
이를 TanStack Query로 바꿔보자!
함수 분리
먼저 데이터를 fetch하는 코드들을 분리한다.
분리하면서 setIsLoading을 지워주고 어디서든 이 함수를 사용할 수 있도록 export 키워드를 붙여준다.
export async function fetchEvents() {
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;
다시 NewEventsSection 파일에 가서 상태 관리 코드와 useEffect Hook이 있는 코드들을 삭제해준다.
데이터 요청을 비롯한 상태 관리들은 이제 TanStack Query로 진행할 것이기 때문이다.
useQuery에 객체 전달하기
useQuery를 사용해 http 요청을 전송하고 데이터를 가져오려고 한다.
const { data, isPending, isError, error } = useQuery({
queryKey: ['events'],
queryFn: fetchEvents,
staleTime: 5000,
// gcTime: 30000,
});
useQuery에 객체를 전달하는데 여기에는 다양한 프로퍼티를 설정할 수 있다.
먼저 queryFn 프로퍼티는 쿼리 함수로, 실제 요청을 전송할 때 실행할 실제 코드를 정의한다.
아까 분리해둔 fetchEvents로 요청을 전송할 것이라서 queryFn으로 fetchEvents를 적어준다.
다음으로 queryKey를 적어준다.
useQuery를 사용할 때 모든 요청에는 쿼리 키가 있다. TanStack Query는 내부에서 이 쿼리 키를 사용해 데이터를 캐시 처리한다.
그래서 나중에 동일한 요청을 전송하면 이전 요청의 응답을 재사용하기 위해 키가 필요하다.
이 키는 배열이며 안에 넣는 요소를 식별자로 지정한다. 배열 안에는 문자열, 배열, 불리언 등 유형이 제한되지 않는다.
staleTime, gcTime은 이전 글에서 짧게 정리했었는데, staleTime은 캐시에 데이터가 있을 때 업데이트된 데이터를 가져오기 위한 요청을 전송하기 전 기다리는 시간이고 gcTime은 가비지 수집 시간이라고 데이터와 캐시를 언제까지 보관할지 제어하는 시간을 말한다.
staleTime(언제까지 신선한 데이터라고 볼지)는 기본값이 0이다. 받아올 때부터 데이터가 달라질 수 있다고 간주한다.
stale한 데이터는 유저가 어떤 액션을 취할 때마다 신선한 데이터를 다시 받아올 수 있다.
gcTime의 기본값은 5분으로 5분이 지나면 캐시에서 사라진다.
아무튼 이렇게 useQuery에 전달할 객체와 프로퍼티를 정했다면 객체를 얻을 수 있다.
이 객체에서는 구조 분해로 data, isPending, isError, error와 같은 프로퍼티를 추출할 수 있다.
data에는 실제 응답 데이터가 값으로 들어 있고, isPending은 요청이 실행중인지를 알려준다.
isError는 오류 응답을 받은 경우 true를 뱉고, error는 발생한 오류에 대한 정보를 갖고 있다.
이 외에도 다양한 프로퍼티들이 있지만 일단은 이 4가지를 사용해 UI를 구성한다.
요청이 실행 되고 있을 때는 로딩 인디케이터가 나오고, 에러가 나온다면 ErrorBlock에 에러의 메세지를 보여준다.
데이터가 있다면 해당 데이터를 map을 사용해 보여주면 된다.
QueryClient 설정하기
if (isPending) {
content = <LoadingIndicator />;
}
if (isError) {
content = (
<ErrorBlock
title="An error occurred"
message={error.info?.message || 'Failed to fetch events.'}
/>
);
}
if (data) {
content = (
<ul className="events-list">
{data.map(event => (
<li key={event.id}>
<EventItem event={event} />
</li>
))}
</ul>
);
}
return (
<section className="content-section" id="new-events-section">
<header>
<h2>Recently added events</h2>
</header>
{content}
</section>
);
}
이 때, "No QueryClient set, use QueryClientProvider to set one"이라는 에러가 뜰 것이다.
이전 게시글에서 잠깐 공식 문서를 훑으며 이야기 했었지만, TanStack Query를 사용하기 위해서는 Provider로 래핑이 필요하다.
import { QueryClientProvider, QueryClient } from '@tanstack/react-query';
const queryClient = new QueryClient();
function App() {
return (
<QueryClientProvider client={queryClient}>
<RouterProvider router={router} />
</QueryClientProvider>
);
}
위와 같이 QueryClientProvider와 QueryClient를 import하고, QueryClient를 인스턴스화 해서 queryClient를 선언한다.
Provider의 client 프로퍼티에 queryClient를 넣어주면 TanStack Query를 사용할 수 있게 된다.
'🌺 TanStack Query' 카테고리의 다른 글
[TanStack Query] Type has no properties in common with type invalidateQueries 에러 해결 (2) | 2024.06.20 |
---|---|
[TanStack Query] 낙관적 업데이트 (0) | 2024.05.07 |
[TanStack Query] useMutation으로 데이터 변경/성공 시 동작 및 쿼리 무효화 (0) | 2024.05.03 |
[TanStack Query] 동적 쿼리와 enabled를 사용한 쿼리 활성/비활성화 (0) | 2024.04.30 |
[TanStack Query] TanStack Query(React Query) 이해하기 (1) | 2024.04.28 |