React Query(리액트 쿼리) - Mutation
iskkiri • 2024년 09월 22일
이번 글에서는 React Query의 mutation에 대해서 알아보겠습니다.
코드와 예제 결과는 Codesandbox에서 직접 확인할 수 있습니다.
Mutation
React Query에서 mutation은 주로 서버에 데이터를 추가, 수정, 삭제하는 작업을 처리하는 기능입니다. useMutation 훅을 사용하여 이러한 변화를 처리할 수 있으며, 서버에 데이터를 보내는 동안 로컬 상태를 업데이트하는 여러 방법이 있습니다. 이 글에서는 세 가지 주요 상태 업데이트 방법을 설명하고, 각각의 장단점을 비교해 보겠습니다.
invalidateQueries를 이용한 상태값 업데이트
invalidateQueries는 쿼리를 무효화하여 React Query가 해당 쿼리 데이터를 다시 가져오도록 하는 방법입니다. 이 방식은 mutation 작업이 성공한 후, 해당 쿼리 키에 연결된 데이터를 무효화하고 서버에서 최신 데이터를 다시 가져옵니다.
const { mutate: createTodo } = useMutation({
mutationFn: createTodoApi,
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: ["TODOS"] });
},
});
장점
- 데이터 일관성: 서버에서 가장 최신의 데이터를 가져오므로, 데이터의 정확성과 일관성을 보장할 수 있습니다.
- 간단함: 데이터를 수동으로 업데이트할 필요 없이, 쿼리를 무효화하여 React Query가 자동으로 새 데이터를 불러옵니다.
단점
- 성능 저하: 매번 서버에서 데이터를 다시 가져오기 때문에 네트워크 요청이 많아져 성능에 영향을 미칠 수 있습니다.
- 비용 증가: 네트워크 요청이 빈번하게 발생하여 서버 부하와 함께 트래픽이 많은 애플리케이션에서는 비용이 증가할 수 있습니다.
setQueryData를 이용한 상태값 업데이트
setQueryData는 쿼리 데이터를 수동으로 업데이트하는 방식입니다. 서버에서 데이터를 다시 불러오는 대신, 로컬에 캐시된 데이터를 바로 업데이트합니다.
const { mutate: createTodo } = useMutation({
mutationFn: createTodoApi,
onSuccess: (response) => {
queryClient.setQueryData<Todo[]>(["TODOS"], (oldData) => {
if (!oldData) return [];
return [
...oldData,
{ id: response.id, title: response.title, completed: response.completed },
];
});
},
});
장점
- 성능 최적화: 서버에 재요청하지 않고 로컬 상태를 직접 업데이트하므로, 네트워크 요청이 줄어들고 성능이 향상됩니다.
- 비용 감소: 네트워크 요청이 줄어들어 네트워크 비용을 절감할 수 있습니다. 특히 트래픽이 많은 애플리케이션에서 효과적입니다.
단점
- 복잡성 증가: 데이터를 수동으로 관리해야 하므로 코드가 더 복잡해질 수 있습니다.
낙관적 업데이트 (Optimistic Update)
낙관적 업데이트는 mutation이 성공할 것이라고 가정하고, 서버에서 응답을 받기 전에 로컬 상태를 먼저 업데이트하는 방식입니다. 만약 서버 요청이 실패하면, 이전 상태로 롤백할 수 있습니다.
const { mutate: createTodo } = useMutation({
mutationFn: createTodoApi,
onMutate: async (payload) => {
await queryClient.cancelQueries({ queryKey: ['TODOS'] });
const previousTodos = queryClient.getQueryData<Todo[]>(['TODOS']);
queryClient.setQueryData<Todo[]>(['TODOS'], (oldData) => {
if (!oldData) return [];
return [...oldData, { id: oldData.length + 1, title: payload.title, completed: false }];
});
return { previousTodos };
},
onError: (_error, _newTodo, context) => {
queryClient.setQueryData(['TODOS'], context?.previousTodos);
},
onSettled: () => {
queryClient.invalidateQueries({ queryKey: ['TODOS'] });
},
});
장점
- 빠른 사용자 경험: 사용자가 서버 응답을 기다리지 않고, 즉시 업데이트된 결과를 볼 수 있습니다.
- 로컬 데이터 유지: 서버 요청이 실패해도 이전 상태로 롤백할 수 있어, 데이터가 안정적으로 관리됩니다.
단점
- 서버 오류 발생 시 데이터 불일치: 만약 서버 요청이 실패하면, 데이터가 잘못된 상태로 잠깐 표시될 수 있습니다.
- 복잡성: 낙관적 업데이트는 성공과 실패를 모두 처리해야 하므로, 코드의 복잡성이 다소 증가합니다.
상태 업데이트 방식을 선택할 때는 개발 환경, 프로젝트의 요구사항에 맞게 결정을 내려야 하며, 각 방법의 장단점을 고려하여 상황에 맞는 최적의 방식을 선택하는 것이 중요합니다.