[TanStack Query] useMutation 어렵지 않아요! 개념부터 사용법까지 ✨

Sara Jo·2025년 3월 27일
post-thumbnail

프론트엔드 개발을 하다 보면 서버와의 데이터 통신은 빼놓을 수 없는 작업이다. 특히 데이터를 수정, 추가, 삭제하는 작업은 대부분의 애플리케이션에서 필수적으로 사용되는데, TanStack Query(구 react-query)에서는 이러한 '변경성 작업'useMutation 훅을 통해 간편하고 효율적으로 처리할 수 있다.

✅ Mutation이란?

먼저 용어부터 짚고 넘어가 보자.

TanStack Query에서 Mutation이란?

데이터를 '읽는(Fetching)' 것이 아닌, '변경(Create, Update, Delete)'하는 모든 작업을 의미한다.

  • 예를 들어 사용자를 추가하거나(POST), 게시글을 수정하거나(PUT), 상품을 삭제하는(DELETE) 작업 등이 모두 mutation이다.

  • 반면, 데이터를 조회하는(GET) 작업은 useQuery를 통해 처리한다.


✅ useMutation 기본 사용법

TanStack QueryuseMutation 훅은 이러한 mutation 작업을 훨씬 더 간단하고, 효율적으로 처리할 수 있도록 도와준다.

📌 기본 사용 예시

import { useMutation } from '@tanstack/react-query'
import axios from 'axios'

const addUser = (newUser) => axios.post('/api/users', newUser)

function AddUserForm() {
  const mutation = useMutation({
    mutationFn: addUser,
    onSuccess: () => {
      alert('유저가 성공적으로 추가되었습니다!')
    },
    onError: (error) => {
      console.error('에러 발생:', error)
    }
  })

  const handleSubmit = (e) => {
    e.preventDefault()
    const newUser = { name: 'Sara', age: 25 }
    mutation.mutate(newUser)
  }

  return <button onClick={handleSubmit}>유저 추가</button>
}

📌 주요 옵션

  • mutationFn: 실제 데이터를 변경하는 비동기 함수
  • onSuccess: 성공 시 실행할 콜백
  • onError: 에러 발생 시 실행할 콜백
  • onSettled: 성공/실패 여부와 관계없이 항상 실행되는 콜백

✅ 자주 쓰는 패턴: 성공 후 캐시 무효화

데이터를 변경한 후에는 기존 useQuery로 가져온 데이터를 새로 고쳐야 할 경우가 많다. 이럴 때는 queryClient.invalidateQueries로 관련 데이터를 무효화(invalidate)하면 된다.

import { useQueryClient } from '@tanstack/react-query'

const queryClient = useQueryClient()

const mutation = useMutation({
  mutationFn: addUser,
  onSuccess: () => {
    queryClient.invalidateQueries({ queryKey: ['users'] })
  }
})

✅ 상태 추적하기 (isLoading, isError, isSuccess)

useMutation은 다음과 같은 상태 값을 제공한다.

  • isLoading: 요청 중 여부
  • isSuccess: 요청 성공 여부
  • isError: 에러 발생 여부
  • error: 에러 객체
  • data: 성공 시 응답 데이터
if (mutation.isLoading) return <p>추가 중입니다...</p>
if (mutation.isSuccess) return <p>추가 완료!</p>
if (mutation.isError) return <p>에러 발생: {mutation.error.message}</p>

🤔 그냥 API 호출해도 되는데, 왜 useMutation을 써야 할까?

이쯤에서 드는 의문이 있다.

"axios로 직접 호출하면 되잖아? 굳이 TanStack Query까지 써야 하나?"

물론 아래처럼 직접 상태를 관리하면서 API를 호출하는것도 가능하다.

const handleSubmit = async () => {
  try {
    setLoading(true)
    await axios.post('/api/user', newUser)
    setSuccess(true)
  } catch (e) {
    setError(e)
  } finally {
    setLoading(false)
  }
}

하지만 이 방식은 몇 가지 단점이 있다.

  • loading, error, success 상태를 직접 구현해야 함

  • API 호출 후 목록을 새로 불러오는 등의 캐시 갱신 작업도 수동으로 해야 함

  • 여러 곳에서 같은 mutation 로직을 사용할 경우 중복된 코드가 생기기 쉬움


✅ 그래서 useMutation을 쓰면 뭐가 좋은데?

1. 상태 관리가 자동

  • isLoading, isError, isSuccess 같은 상태를 TanStack Query가 알아서 제공해준다.

  • 로딩 스피너, 에러 메시지, 성공 메시지 등을 쉽게 처리할 수 있다.

const mutation = useMutation(...)
mutation.isLoading // 로딩 중인지
mutation.isError   // 에러 발생했는지
mutation.error     // 에러 정보

2. 성공 후 자동 캐시 갱신 가능

데이터가 바뀌었으면 기존 목록도 새로 받아와야 하잖아요?

queryClient.invalidateQueries를 활용하면 자동으로 해당 데이터 갱신이 가능하다.

onSuccess: () => {
  queryClient.invalidateQueries({ queryKey: ['userList'] })
}

3. 재사용성과 코드 통일성

  • 여러 컴포넌트에서 동일한 mutation 로직을 재사용할 수 있다.

  • 훅으로 캡슐화해 놓으면 가독성과 유지보수성도 훨씬 좋아진다.

// hooks/useCreateUser.ts
export const useCreateUser = () => {
  return useMutation({ mutationFn: createUserAPI })
}

4. Devtools로 요청 흐름 추적 가능

TanStack Query Devtools를 사용하면 요청 흐름과 상태를 시각적으로 확인할 수 있다.
(단순 fetch만 썼다면 직접 콘솔 로그를 찍거나 디버깅해야함)

5. 에러 리트라이 등 고급 설정

실패 시 자동 재시도, delay 조절 등 다양한 옵션을 사용할 수 있다.

useMutation({
  mutationFn,
  retry: 3,
  retryDelay: 1000,
})

🧩 언제 그냥 fetch/axios를 쓰고, 언제 useMutation을 써야 할까?

상황추천 방식
간단한 데모, 빠른 테스트용그냥 axios/fetch
데이터 변경이 복잡하지 않고, 재사용성이 낮을 때axios + 상태 직접 처리도 OK
✅ 실서비스에서 상태 관리, 캐시 갱신, 재사용성, 일관된 UX가 필요할 때useMutation

📝 요약

useMutation은 단순한 API 호출을 넘어, 상태 관리, 응답 처리, 캐시 동기화까지 한 번에 해결할 수 있는 강력한 도구다. 특히 실무에서는 반복적으로 마주치는 "추가 / 수정 / 삭제" 요청을 깔끔하게 추상화해주기 때문에, 일관된 UX를 유지하면서도 유지보수가 쉬운 코드를 작성할 수 있게 해준다.

직접 상태를 관리하는 방식(fetch/axios)도 가능하지만,

  • 로딩 / 에러 / 성공 상태를 일일이 구현해야 하고,
  • 성공 후 캐시를 수동으로 갱신해야 하며,
  • 여러 컴포넌트에서 같은 로직을 반복하게 되는 단점이 있다.

반면, useMutation을 사용하면

  • 상태 관리가 자동화되고
  • 성공 후 캐시 갱신도 간단하며
  • 코드 재사용성과 통일성이 훨씬 높아진다.

📌 실서비스에서 효율적인 데이터 변경 로직을 구현하고 싶다면, useMutation을 사용해보기를 적극추천한다!

0개의 댓글