React Query는 서버 상태 관리를 위한 라이브러리이다.
기존의 Redux, recoil, zustand 등 전역상태관리 도구들이 client 상태관리에 중점을 뒀다면,
React query는 서버데이터를 효율적으로 관리하는데 특화되어 있다.
useQuery
useMutation
useInfiniteQuery
QueryClient, QueryClientProvider
const { data } = useQuery(['user'], fetchUser, {
staleTime: 1000 * 60 * 5, // 5분 동안 데이터를 신선한 상태로 유지
});
const { data } = useQuery(['posts'], fetchPosts, {
cacheTime: 1000 * 60 * 10, // 10분 동안 캐시 유지
});
const { data } = useQuery(['notifications'], fetchNotifications, {
refetchOnWindowFocus: true, // 기본값, 창 포커스 시 리페치
});
const { data } = useQuery(['cryptoPrice'], fetchCryptoPrice, {
refetchInterval: 1000 * 5, // 5초마다 리페치
});
// todo에서의 사용 예
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
// 1. Todo 데이터를 가져오는 함수
const fetchTodos = async () => {
const res = await fetch('/api/todos');
if (!res.ok) throw new Error('Failed to fetch todos');
return res.json();
};
// 2. Todo를 추가하는 함수
const addTodo = async (newTodo) => {
const res = await fetch('/api/todos', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(newTodo),
});
if (!res.ok) throw new Error('Failed to add todo');
return res.json();
};
function TodoList() {
// QueryClient를 가져옴 (캐시 관리용).
const queryClient = useQueryClient();
// 3. Todo 리스트를 가져오기 위한 useQuery
const { data, isLoading, isError, error } = useQuery('todos', fetchTodos);
// 4. Todo를 추가하기 위한 useMutation
const { mutate } = useMutation(addTodo, {
onSuccess: () => {
// 성공 시 todos 데이터를 무효화하여 새 데이터를 가져옵니다.
queryClient.invalidateQueries('todos');
},
});
// 5. 버튼 클릭 이벤트로 새로운 Todo 추가
const handleAddTodo = () => {
const newTodo = {
title: `New Todo ${Date.now()}`,
completed: false,
};
mutate(newTodo); // 새로운 Todo 추가
};
if (isLoading) return '로딩중...';
if (isError) return `에러가 발생했습니다: ${error.message}`;
return (
<div>
<h1>Todo List</h1>
{/* 6. 버튼으로 새로운 Todo 추가 */}
<button onClick={handleAddTodo}>Add New Todo</button>
{/* 7. Todo 리스트 출력 */}
<ul>
{data.map((todo) => (
<li key={todo.id}>{todo.title}</li>
))}
</ul>
</div>
);
}
export default TodoList;
에러 핸들링 간소화
React Query는 API 요청의 상태(isLoading, isError, isSuccess, status)를 자동으로 제공하므로, 상태 관리를 별도로 구현하지 않아도 됨.
Retry 메커니즘 제공
React Query는 기본적으로 요청 실패 시 최대 3회 재시도를 수행하며, 이는 retry 옵션으로 간단히 조정 가능합니다.
const { isError, error } = useQuery(['data'], fetchData, {
retry: 2, // 실패 시 최대 2번 재시도
});
if (isError) {
console.error('Error occurred:', error.message);
}
1. 실시간 데이터 동기화
function RealTimeData() {
const { data } = useQuery('realtime-data', fetchData, {
refetchInterval: 1000, // 1초마다 자동 갱신
});
}
2. 낙관적 업데이트
낙관적 업데이트란, api 요청이 성공할거라고 낙관적으로 예상하고 ui를 먼저 업데이트하는 방식
인스타 좋아요의 경우 사용되며, 실패 시 이전 데이터를 통해 다시 복원할 수 있다.
const queryClient = useQueryClient();
const { mutate } = useMutation(updateTodo, {
onMutate: async (newTodo) => {
// 이전 쿼리 데이터 백업
const previousTodos = queryClient.getQueryData('todos');
// 낙관적으로 UI 업데이트
queryClient.setQueryData('todos', old => {
return old.map(todo =>
todo.id === newTodo.id ? newTodo : todo
);
});
return { previousTodos };
},
onError: (err, newTodo, context) => {
// 에러시 롤백
queryClient.setQueryData('todos', context.previousTodos);
}
});