본문 바로가기

Study/실무

useMutation

 

 

useMutation ?

  • 데이터를 생성 / 업데이트 / 삭제할 때 주로 사용합니다. <-> useQuery
  • optimistic update을 활용해서 성공을 예상하며 미리 UI부터 갱신할 수 있습니다.

 

 

Option

  • onMutate: (variables:TVariables) => Promise<TContext|void>|TContext|void
    • mutationFn이 실행되기 전에 먼저 실행할 함수입니다.
    • mutation 함수가 전달받은 파라미터가 동일하게 전달됩니다.
    • optimistic update 사용 시 유용한 함수입니다.
    • 여기서 반환된 값은 onError, onSettled 함수에 전달됩니다. 

  • onSuccess: (data: TData, variables: TVariables, context?: TContext) => Promise<unknown> | void
    • mutation()이 성공하면 결과를 전달할 때 실행 됩니다.
      • invalidationQueries(QueryKey)로 해당 쿼리를 invalidate 하고 refetch
      • setQueryData로 직접 캐싱된 쿼리 데이터를 수정. (Optimistic Update) refetch가 일어나지 않음.

  • onError: (err: TError, variables: TVariables, context?: TContext) => Promise<unknown> | void
    • mutation이 에러를 만났을 때 실행됩니다.

  • onSettled: (data: TData, error: TError, variables: TVariables, context?: TContext) => Promise<unknown> | void
    • mutation()의 성공 / 에러 여부에 상관없이 해당 데이터를 전달받습니다. 

  • mutationFn (variables: TVariables) => Promise<TData>
    • Required
    • 비동기 작업을 수행하고 프로미스를 반환하는 함수입니다. (쉽게 말해 api 요청하는 함수)
    • variables 는 mutate가 전달하는 객체입니다.

 

 

Return

  • mutate: (variables: TVariables, { onSuccess, onSettled, onError }) => void
    • mutation을 실행시키는 함수입니다.
    • variables 는 mutationFn에 전달하는 객체입니다.

 

 

코드 예시

import React from "react";
import axios from "axios";
import { useMutation } from "react-query";

import "./App.css";

function App() {
  const fetchAdd = async (info) => {
    const { data } = await axios.post(`/add`, info);

    return data;
  };

  const { mutate, isLoading, isSuccess, isError } = useMutation(fetchAdd, {
    onMutate: (variables) => {
      // variables : {id: 1}
      console.log("onMutate", variables);
    },
    onError: (error, variables, context) => {
      // error
    },
    onSuccess: (data, variables, context) => {
      console.log("success", data, variables, context);
    },
    onSettled: (data, error, variables, context) => {
      // end
    },
  });

  const handleSubmit = () => {
    // onMutate 실행 => 성공시 onSuccess 실행 => 끝나면 onSettled 실행
    mutate({ id: 1 });
  };
}
export default App;
 
 

 

update 이후 Get 요청을 통한 최신화

  • react-query 장점으로 Update후에 Get 요청을 자동으로 진행 할 수 있습니다.
  • mutation 함수가 성공할 때, unique key를 invalidateQueries에 넣어주면 됩니다.
    • invalidateQueries가 실행되면 해당 Query는 무효화되며 refetching을 시도합니다.
    • 즉 사용자가 새로고침을 하지 않아도 데이터가 갱신 됩니다.
const queryClient = useQueryClient();

const mutation = useMutation(fetch, {
  onSuccess: () => {
    // postTodo가 성공하면 todos로 맵핑된 useQuery api 함수를 실행합니다.
    queryClient.invalidateQueries("key");
  }
});
  • 해당 Query에 대해 refetching을 원하지 않고 무효화만 원한다면 refetchActive 옵션을 사용합니다.
queryClient.invalidateQueries("key", {
 refetchActive: false, 
});

 

 

Optimistic Update

  • useMutation이 성공할 것이라 가정하고 미리 화면의 UI를 바꾸고 나서, 결과에 따라 확정 / 롤백하는 방식입니다.
  • setQueryData 옵션을 사용합니다.
import React from "react";
import axios from "axios";
import { useMutation } from "react-query";

import "./App.css";

function App() {
  const fetchAdd = async (info) => {
    const { data } = await axios.post(`/add`, info);

    return data;
  };

  const queryClient = useQueryClient();

  const { mutate, isLoading, isSuccess, isError } = useMutation(fetchAdd, {
    onMutate: async (variables) => {
      // 요청한 Query 취소 함수
      // 즉 해당 Query에 대한 refetching을 막는 것 => onMutate에서 수행되는 것들을 덮어쓰지 않기 위해
      await queryClient.cancelQueries("key");

      // 기존 Query를 가져오는 함수 ( 존재하지 않으면 undefinde 반환 )
      const previousValue = queryClient.getQueryData("key");

      if (previousValue) {
        // setQueryData(): Query의 캐시된 데이터를 즉시 업데이트하는 동기 함수 ( Query가 존재하지 않으면 생성 )
        // 전달받은 variables값을 즉시 새로운 데이터로 업데이트
        queryClient.setQueryData("key", (oldData) => [...oldData, variables]);
      }

      // 이전 값 리턴
      return { previousValue };
    },
    onError: (error, variables, context) => {
      if (context?.previousValue) {
        // error가 발생하면 onMutate에서 반환된 값으로 다시 롤백
        queryClient.setQueryData("key", context.previousValue);
      }
    },
    onSuccess: (data, variables, context) => {},
    onSettled: (data, error, variables, context) => {
      // mutation이 완료되면 성공 유무와 관계없이 쿼리를 무효화 시키고 새로 갱신
      queryClient.invalidateQueries("key");
    },
  });

  const handleSubmit = () => {
    // onMutate 실행 => 성공시 onSuccess 실행 => 끝나면 onSettled 실행
    mutate({ id: 1 });
  };
}
export default App;

 

 

 

 

 

 

 

 

참조

https://velog.io/@woodong/3.-useMutation

https://velog.io/@kimhyo_0218/React-Query-%EB%A6%AC%EC%95%A1%ED%8A%B8-%EC%BF%BC%EB%A6%AC-useMutation-%EA%B8%B0%EB%B3%B8-%ED%8E%B8

'Study > 실무' 카테고리의 다른 글

React-Router v6  (0) 2022.10.05
useQuery  (0) 2022.10.05
Typescript Type vs interface  (0) 2022.10.04
window.location.href vs useNavigate vs Link  (0) 2022.10.04
web3-react를 이용한 메타마스크,코인베이스 지갑 연동  (0) 2022.10.04