useMutation
: React Query 라이브러리에서 제공하는 훅으로, 변이(데이터 추가, 수정, 삭제)를 수행하고 그 결과 처리함.
1) import { useMutation } from 'react-query';
2) 변이 함수 정의.
변이 함수는 실제로 데이터를 추가, 수정, 삭제하는 작업을 수행
---> api 폴더에 todos.js에 만들어줌.
3) useMutation 훅을 사용하여 변이 처리
---> 예시 const editMutation = useMutation(editTodo)
4) 변이를 실행하고 변이의 실행 결과 처리. editMutation은 객체로 반환되며,
mutate와 isLoading, isError, isSuccess 등과 같은 속성을 포함.
isLoading: 변이가 실행 중인지 여부 나타냄
isError: 변이 실행 중에 오류가 발생했는지 여부를 나타냄
isSuccess: 변이가 성공적으로 완료되었는지 여부를 나타냄
// [출처] : 공식문서
function App() {
const mutation = useMutation(newTodo => {
return axios.post('/todos', newTodo)
})
return (
<div>
{mutation.isLoading ? (
'Adding todo...'
) : (
<>
{mutation.isError ? (
<div>An error occurred: {mutation.error.message}</div>
) : null}
{mutation.isSuccess ? <div>Todo added!</div> : null}
<button
onClick={() => {
mutation.mutate({ id: new Date(), title: 'Do Laundry' })
}}
>
Create Todo
</button>
</>
)}
</div>
)
}
5) 필요에 따라 onSuccess, onError, onSettled 등의 옵션을 사용하여 변이 실행 후 추가적인 로직을 처리할 수도 있음.
--> onSuccess
는 useMutation
훅의 옵션 중 하나, 변이가 성공적으로 완료되었을 때 실행할 콜백 함수를 정의하는 역할. onSuccess 옵션에 콜백 함수를 전달하면, 해당 함수는 변이가 성공적으로 완료되었을 때 호출.
1) useMutation 코드 반복 줄이기
사실 지금까지 컴포넌트 분리만 해봤지 반복되는 코드 줄이는 건 한번도 해본 적이 없는데... useMutation을 사용하는 부분에 반복되는 곳이 많아 정리할 필요가 있어 시도해봤다. 근데 도통 모르겠음...
원본
const editMutation = useMutation(editTodo, {
onSuccess: () => {
// 불러왔던 todos를 무효화시키고 다시 불러옴(=바로바로 Refresh)
queryClient.invalidateQueries("todos");
},
});
const deleteMutation = useMutation(deleteTodo, {
onSuccess: () => {
queryClient.invalidateQueries("todos");
},
});
1차 시도
const onSuccess = () => {
queryClient.invalidateQueries("todos");
};
const editMutation = useMutation(editTodo, {
onSuccess,
});
const deleteMutation = useMutation(deleteTodo, {
onSuccess,
});
이렇게 하면 queryClient.invalidateQueries("todos") 가 한줄 줄긴 줄었지만... 크게 의미가 없는 것 같아 커스텀 훅으로 만들어 분리해봤다.
📌 2차 시도
components폴더에 newTodosMutation.js
파일을 만들어 mutation을 정의하고
import { useMutation, useQueryClient } from "react-query";
const useTodosMutation = (mutationFn) => {
const queryClient = useQueryClient();
const onSuccess = () => {
queryClient.invalidateQueries("todos");
};
return useMutation(mutationFn, {
onSuccess,
});
};
export default useTodosMutation;
함수가 실행되어야 할 List.jsx파일에 아래와 같이 추가해주었다.
const editMutation = useTodosMutation(editTodo);
const deleteMutation = useTodosMutation(deleteTodo);
그리고 버튼 누르면 실행될 함수 안에서 함수 호출..!
그럼 클릭 함수가 연결된 버튼이 눌릴 때마다
editMutation.mutate(editedTodo)
를 호출하여 editedTodo
를 변이 함수(=editTodo)로 전달하여 데이터 수정
deleteMutation.mutate(id)
를 호출하여 id를 변이 함수(=deleteTodo)로 전달하여 데이터 삭제
(여기서 .mutate
는 mutate 함수를 말하는데 해당 변이를 실행하는 역할을 한다)
🤔 여기서 드는 의문
데이터 추가, 수정, 삭제는 axios.~~로 다 가능한데 굳이 useMutation를 사용하는 이유가 뭐지?
--> Axios 와 React Query의 useMutation를 구분하자.
📌 Axios
는 HTTP 요청을 보내기 위한 간편한 인터페이스를 제공하는 독립적인 라이브러리.
GET, POST, PATCH 등과 같은 다양한 HTTP 메서드를 지원하며, API와 상호작용하여 데이터를 전송하고 수신할 수 있다.
한편, React Query 라이브러리의 일부인 useMutation
훅은 데이터 변경(추가, 업데이트, 삭제 등)을 처리하며, 자동 캐싱, 상태 관리, 쿼리 시스템과의 통합과 같은 추가 기능을 제공한다. HTTP 클라이언트인 Axios를 보완하는 역할로 추가적인 기능을 통해 데이터 변경 작업을 보다 향상시킨다.
즉, axios.post와 axios.patch는 데이터 변경 작업에 직접 사용되는 HTTP 클라이언트 메서드이고, useMutation은 React Query에서 데이터 변경 작업을 관리하고 UI 업데이트를 자동화하는 기능을 제공하는 훅이다.
결론: 나는 변이가 성공했을 때 추가적인 동작(Query Invalidation 무효화)을 수행해야 하기에 useMutation이 필요하다.