React Query는 fetching, caching, 서버 데이터와 동기화 등의 기능을 지원해주는 라이브러리로, 서버로부터 데이터를 가져오거나 변경하는 등 다양한 작업을 쉽게 할 수 있도록 도와줍니다ㅏ. 가장 큰 장점인 캐싱은 반복적인 비동기 데이터 호출을 방지하고 서버 부하를 줄입니다.
쿼리는 서버로부터 데이터를 읽어오는 GET 요청 작업을 실행할 때 사용합니다
import { useQuery } from '@tanstack/react-query'
function Todos() {
const query = useQuery({ queryKey: ['todos'], queryFn: getTodos })
return (
<ul>
{query.data?.map((todo) => (
<li key={todo.id}>{todo.title}</li>
))}
</ul>
);
}
쿼리와 달리 뮤테이션은 일반적으로 서버 상태를 변경하는 작업인 데이터를 생성/업데이트/삭제하거나 서버의 사이드 이펙트(side effect, 예상치 못한 부수 효과로 의도치 않은 결과)를 수행할 때 사용합니다. 이를 위해 useMutation
훅을 사용합니다. 여러 가지 콜백 함수 옵션(onMutate, onError 등)과 함께 사용해 다양한 경우에 대응할 수 있습니다
import { useMutation } from '@tanstack/react-query'
function Todos() {
const mutation = useMutation({
mutationFn: postTodo,
onMutate: () => {
// 뮤테이션이 발생하기 직전에 호출됨. 옵티미스틱 업데이트 작업 등
},
onError: () => {
// 뮤테이션이 실패하면 호출됨. 에러 처리 로직 작성
},
onSuccess: () => {
// 뮤테이션이 성공적으로 완료된 후 호출됨
// Invalidate and refetch
queryClient.invalidateQueries({ queryKey: ['todos'] })
},
onSettled: () => {
// 성공, 실패 여부와 관계없이 요청 후 마지막에 실행됨
// 클린업 작업이나 쿼리 무효화 등
}
})
return (
<button
onClick={() => {
mutation.mutate({
id: Date.now(),
title: 'Do Laundry',
})
}}
>
Add Todo
</button>
);
}
옵티미스틱 업데이트는 서버 응답을 기다리지 않고 즉시 UI를 업데이트하는 방식으로 사용자에게 좋은 경험을 제공할 수 있습니다. 서버 응답이 실패할 경우 롤백(원상태로 되돌리기) 로직을 포함해야 UI와 실제 데이터 상태가 유지될 수 있습니다. useMutaion
훅의 onMutate
콜백 함수에서 구현할 수 있습니다.
function Todos() {
const queryClient = useQueryClient()
...
const mutation = useMutation({
mutationFn: postTodo,
onMutate: async (newTodo) => {
const previousTodos = queryClient.getQueryData('todos');
// 즉시 새로운 todo를 추가하여 UI 업데이트
queryClient.setQueryData('todos', old => [...old, newTodo]);
return { previousTodos };
},
onError: (err, newTodo, context) => {
// 실패 시 롤백 수행
queryClient.setQueryData('todos', context.previousTodos);
},
...
})
return ();
}