3. useMutation

우동이·2022년 4월 21일
3

React-Query

목록 보기
3/3
post-thumbnail
post-custom-banner

1. useMutation이란?

  • 데이터를 생성 / 업데이트 / 삭제할 때 주로 사용합니다.
    • 데이터의 변화가 이루어질 때 다시 서버로 부터 Get 요청을 통해 최신 데이터를 유지할 수 있습니다.
    • 또한 optimistic update을 활용해서 미리 UI부터 갱신할 수 있습니다.
  • 기본적으러 useQuery와 사용방법이 거의 동일합니다.
import { useMutation } from "react-query";

const { data, isLoading, mutate } = useMutation(fetch, options);
  • Option과 Return값을 더 자세히 알고 싶으면 공식문서 참조

2. Option

  • onMutate: (variables) => Promise
    • mutation() 이 실행하기 전 먼저 실행되고 mutation()함수가 전달받은 파라미터가 동일하게 전달됩니다.
  • onSuccess: (data, variables, context) => Promise
    • mutation()이 성공하면 결과를 전달할 때 실행 됩니다.
  • onError: (err, variables, context) => Promise
    • mutation()과정에서 에러가 발생되면 실행됩니다.
  • onSettled: (data, error, variables, context) => Promise
    • mutation()의 성공 / 에러 상황에 따라 해당 데이터를 전달받습니다.

3. Return 값

  • mutate: (variables, { onSuccess, onSettled, onError }) => void
    • mutation을 발생시키는 함수이며 파라미터에 값을 전달할 경우 fetch에 전달됩니다.
    • 실질적으로 API 호출을 통해 생성 / 업데이트 / 삭제 수행
    • onSuccess, onError, onSettled,는 위 설명과 동일
      • 만약 useMutationmutate() 둘다 해당 옵션을 사용할 경우 useMutation부터 실행
      • 컴포넌트가 unmount 되면 추가 콜백은 실행되지 않습니다.

4. 코드 예시

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;

5. 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, 
});

6. Optimistic Update

  • Optimistic은 사용자가 어떤 요청을 했을 때 무조건 성공했다고 가정하여 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;

7. 커스텀 훅 활용 + TypeScript

import { AxiosError } from "axios";
import { useMutation, UseMutationResult } from "react-query";

export default function useCustomMutation(): UseMutationResult<
  valueType,
  AxiosError,
  valueType
> {
  return useMutation(fetch, {
    onSuccess: (data) => {
      console.log(data); 
    },
    onError: (error) => {
      console.error(error);
    },
  });
}

// 활용
const { mutate } = useCustomMutation();

const handle = () => {
  mutate(
    {
      id: 1,
    },
    {
      onSuccess: () => {
        // 추가 콜백 함수 구현
      },
    }
  );
}
profile
아직 나는 취해있을 수 없다...
post-custom-banner

0개의 댓글