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,
는 위 설명과 동일
- 만약
useMutation
과 mutate()
둘다 해당 옵션을 사용할 경우 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) => {
console.log("onMutate", variables);
},
onError: (error, variables, context) => {
},
onSuccess: (data, variables, context) => {
console.log("success", data, variables, context);
},
onSettled: (data, error, variables, context) => {
},
});
const handleSubmit = () => {
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: () => {
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) => {
await queryClient.cancelQueries("key");
const previousValue = queryClient.getQueryData("key");
if (previousValue) {
queryClient.setQueryData("key", (oldData) => [...oldData, variables]);
}
return { previousValue };
},
onError: (error, variables, context) => {
if (context?.previousValue) {
queryClient.setQueryData("key", context.previousValue);
}
},
onSuccess: (data, variables, context) => {},
onSettled: (data, error, variables, context) => {
queryClient.invalidateQueries("key");
},
});
const handleSubmit = () => {
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: () => {
},
}
);
}