요즘 프론트엔드 구직시장에 요구사항으로 항상 써져있는 문구가 있다
tanstack-query 사용 가능자!!!
tanstack-query는 서버 상태를 클라이언트에서 효율적으로 가져오고, 캐싱하고, 동기화하며 관리할 수 있는 도구이다.
한마디로 서버 상태 관리에 특화된 라이브러리!
뭐길래 요래 유명한지 한번 알아보자
TanStack Query (formerly known as React Query) is often described as the missing data-fetching library for web applications, but in more technical terms, it makes fetching, caching, synchronizing and updating server state in your web applications a breeze.
TanStack Query(예전 이름 React Query)는 웹 앱에서 데이터를 가져오는 데 필요한 라이브러리라고 흔히 말하는데, 좀 더 기술적으로 말하면 서버 상태를 가져오고, 캐싱하고, 동기화하고, 업데이트하는 걸 엄청 쉽게 만들어준다.
@tanstack/react-query 를 설치해준다
npm i @tanstack/react-query
모든 라이브러리들이 그렇듯 최상위 컴포넌트에서 앱을 감싸주면 된다
패키지를 다룰 때 이 패키지를 순수 프레임워크로만 만든다고 생각하면 너무나 당연한 절차다
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
const queryClient = new QueryClient();
function App() {
return (
<QueryClientProvider client={queryClient}>
<YourApp />
</QueryClientProvider>
);
}
기존에 특정 API를 useHook으로 만들어서 사용하고 있었는데
이 파일의 코드에 한번 tanstack-query를 적용해보자
import { useState, useEffect } from "react";
import { Content } from "@/types/index";
import api from "@/api/config";
const useFetchContents = () => {
const [contents, setContents] = useState<Content[]>([]);
const [loading, setLoading] = useState<boolean>(true);
const [error, setError] = useState<any | null>(null);
useEffect(() => {
const fetch = async () => {
try {
const { data } = await api.get<Content[]>("/assignments");
setContents(data);
} catch (err: any) {
setError(err.response?.data?.error || err.message);
} finally {
setLoading(false);
}
};
fetch();
}, []);
return {
data: contents,
loading,
error,
};
};
export default useFetchContents;
import { useQuery } from "@tanstack/react-query";
import { Content } from "@/types/index";
import api from "@/api/config";
const useFetchContents = () => {
const { data, isLoading, error } = useQuery<Content[], Error>({
queryKey: ["contents"], // Unique key for the query
queryFn: async () => {
const { data } = await api.get<Content[]>("/assignments");
return data;
},
});
return {
data: data ?? [],
loading: isLoading,
error,
};
};
export default useFetchContents;
기존 커스텀 훅 파일에 적용을 해서 불필요한 리턴을 하고 있는데,
간단한 구조라면 아래처럼 컴포넌트에서 직접 사용하는 것도 가능하다
const MyComponent = () => {
const { data, isLoading, error } = useQuery<Content[], Error>({
queryKey: ["contents"], // Unique key for the query
queryFn: async () => {
const { data } = await api.get<Content[]>("/assignments");
return data;
},
});
return <div>my-component</div>
};
코드가 많이 간결해졌다
실무에서는 쿼리의 동작을 상황에 맞게 조절해야 할 때가 많다.
그럴 때 사용되는 주요 옵션들과 기본값을 함께 정리해보자.
옵션 | 설명 | 기본값 |
---|---|---|
enabled | 조건부로 쿼리 실행 여부를 제어 | true |
staleTime | 데이터가 stale로 간주되기까지 걸리는 시간(ms) | 0 |
cacheTime | unmount 후에도 데이터를 유지하는 시간(ms) | 300000 (5분) |
refetchOnWindowFocus | 창이 다시 포커스될 때 refetch | true |
retry | 요청 실패 시 재시도 횟수 | 3 |
refetchInterval | 일정 주기로 refetch (ms 단위) | false (사용 안 함) |
select | 쿼리 결과를 변형할 수 있는 함수 | 없음 |
onSuccess, onError | 쿼리 성공/실패 시 실행되는 콜백 | 없음 |
const { data, isLoading } = useQuery({
queryKey: ["todos"],
queryFn: fetchTodos,
enabled: !!userId, // 조건부 실행
staleTime: 1000 * 60 * 5, // 5분 간 fresh
cacheTime: 1000 * 60 * 10, // 10분 동안 메모리 유지
refetchOnWindowFocus: false, // 창 포커스 시 refetch 안함
retry: 2, // 실패 시 2회까지 재시도
});