
이전 시간에는 리액트 쿼리의 useQuery에 대해서 알아보았습니다.
오늘은 리액트 쿼리의 update, put, delete, post에 사용되는 useMutation에 대해서 알아보도록 하겠습니다.
위에서 말씀드린 것 같이 리액트 쿼리에서 서버에 updata, put, delete, post 등 서버의 상태를 변경할 때 사용하는 것이 useMutation입니다.
근데 여기서 또 궁금한 점이 있습니다. 굳이 하나의 훅을 사용하면 되는 거지 왜 리액트 쿼리는 useQuery 와 useMutation으로 두개의 훅을 만들어 구분하였을까요?
저도 궁금해서 찾아봤습니다.
간단하게 mutation이라는 의미는 변형, 가변이라는 뜻입니다. 프로그래밍 세계에서는 데이터를 변경한다는 의미라고 합니다.
데이터 변경은 사이드 이펙트를 발생시키지만 서버에 데이터를 요청하여 받아오는 것은 사이드 이펙트를 발생시키지 않습니다.
리액트에서 데이터가 필요할 때 서버에게 데이터를 요청하여 받아오기도 하지만 일반적으로 컴포넌트가 마운트 되면 자동으로 서버에 데이터를 요청하여 데이터를 받아와야 합니다.
get 기능을 선언적으로 자동으로 데이터를 요청하여 받아 올 수 있도록 하고 updata, put, delete, post 등의 기능은 컴포넌트가 마운트 되면 자동으로 되는 것이 아닌 사용자가 어떤 행동을 하여 발생하는 것이기 때문에 선언적이 아니라 명령형으로 사용되어야 합니다. 그래서 리액트 쿼리는 두개의 훅을 만들어 용도를 분리하였다고 합니다.
그럼 useMutation에 대해서 알아보도록 하겠습니다.
useMutation의 반환값은 useQuery 와 같습니다. useQuery 와 다른 점은 첫번째 인자에 비동기 함수를 전달한다는 것입니다. 두번째 인자에는 옵션을 작성하면 됩니다.
그리고 반환값으로 mutate를 반환받아 첫번째 인자로 전달한 비동기 함수를 호출 할 수 있습니다.
예를 어떤 UI를 클릭하면 어떤 데이터를 삭제한다고 할 때 mutate()로 useMutation의 첫 번째 인자로 전달한 비동기 함수가 호출되는 것입니다. 추가적으로 mutate에 인자를 전달해 그 인자가 비동기 함수가 호출될 때 비동기 함수에 인자로 전달할 수 있습니다.
그럼 간단하게 코드로 보시면서 조금 더 공부해 보겠습니다.
const App = () => {
const deleteFunc = async (data) => {
// 삭제 요청 코드
};
const { mutate: dataDelete } = useMutation((data)=>deleteFunc);
return (
<div>
<button onclick={() => dataDelete(1)}>데이터 삭제</button>
</div>
);
};
저는 데이터 삭제 버튼을 클릭하면 useMutation의 첫번째 인자에 전달한 삭제 요청 함수에 1이 전달되어 삭제 요청이 되는 코드를 간단하게 작성해 보았습니다.
위와 같이 useMutation 을 사용하면 updata, put, delete, post 등의 비동기 처리를 쉽게 할 수 있습니다.
useMutation 을 통해서 서버 데이터에 사이드 이펙트를 발생시킨 후 서버에 데이터를 다시 요청해서 데이터를 받아와 화면에 업데이트 해줘야 합니다.
리액트 쿼리는 이 과정을 쉽게 처리할 수 있도록 invalidataQueries를 제공합니다.
방법은 다시 실행하고 싶은 쿼리키를 인자로 전달하기만 하면 됩니다.
어떤 데이터를 삭제하고 getData라는 쿼리키를 가진 쿼리를 이용해 다시 데이터를 서버에 요청해서 받아와 화면을 업데이트한다고 생각해 봅시다.
const deleteFunc = async (data) => {
// 삭제 요청 코드
};
const queryClient = useQueryClient();
const { mutate: dataDelete } = useMutation((data) => deleteFunc(data), {
onSuccess: () => {
queryClient.invalidataQueries(["getData"]);
},
});
위와 같이 useMutate의 세번째 옵션에 onSucess에 invalidataQueries를 사용하면 됩니다. 데이터의 삭제가 성공하면 getData 쿼리를 다시 실행시켜서 서버에 데이터를 요청해 받아오는 것입니다.
위의 코드에서 설명하지 않은 useQueryClient()는 컴포넌트 최상단에 리액트 쿼리를 사용하기 위해서 new QueryClient로 객체를 생성해 QueryClientProvider 컴포넌트의 client props로 전달한 것이 기억날 것입니다.
그 객체를 useQueryClient로 불러와 사용할 수 있습니다.
지금까지 리액트 쿼리의 사이드 이펙트를 발생시킬 때 사용하는 useMutation 에 대해서 알아보았습니다. 다음 시간에는 리액트 쿼리의 좋은 장점 중 하나인 캐싱 기능을 살펴보고 리액트 쿼리는 서버에 요청해서 받아 온 데이터를 어떻게 관리하고 어떻게 캐싱을 정의하고 사용할 수 있는지 알아보도록 하겠습니다. 감사합니다.