React Query(리액트 쿼리) - Mutation

iskkiri2024년 09월 22일
React Query
Mutation
useMutation
invalidateQueries
setQueryData
Optimistic Update
낙관적 업데이트
React Query(리액트 쿼리) - Mutation

이번 글에서는 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'] });
  },
});

 

장점

 

  • 빠른 사용자 경험: 사용자가 서버 응답을 기다리지 않고, 즉시 업데이트된 결과를 볼 수 있습니다.
  • 로컬 데이터 유지: 서버 요청이 실패해도 이전 상태로 롤백할 수 있어, 데이터가 안정적으로 관리됩니다.

 

단점

 

  • 서버 오류 발생 시 데이터 불일치: 만약 서버 요청이 실패하면, 데이터가 잘못된 상태로 잠깐 표시될 수 있습니다.
  • 복잡성: 낙관적 업데이트는 성공과 실패를 모두 처리해야 하므로, 코드의 복잡성이 다소 증가합니다.

 

 

상태 업데이트 방식을 선택할 때는 개발 환경, 프로젝트의 요구사항에 맞게 결정을 내려야 하며, 각 방법의 장단점을 고려하여 상황에 맞는 최적의 방식을 선택하는 것이 중요합니다.

React Query(리액트 쿼리) - Mutation