πŸš€ TanStack Query둜 μ„œλ²„ μƒνƒœ κ΄€λ¦¬ν•˜κΈ° – useMutation

박애리·2025λ…„ 2μ›” 24일

React μ• ν”Œλ¦¬μΌ€μ΄μ…˜μ—μ„œ μ„œλ²„ μƒνƒœλ₯Ό 효율적으둜 κ΄€λ¦¬ν•˜λŠ” 방법 쀑 ν•˜λ‚˜λŠ” TanStack Queryλ₯Ό μ‚¬μš©ν•˜λŠ” κ²ƒμž…λ‹ˆλ‹€.
μ˜€λŠ˜μ€ μ„œλ²„ 데이터λ₯Ό μ—…λ°μ΄νŠΈν•  λ•Œ μœ μš©ν•œ useMutation 훅을 μ‚΄νŽ΄λ³΄κ³ , μ œκ°€ μ‹€μˆ˜ν–ˆλ˜ κ²½ν—˜μ„ κ³΅μœ ν•˜λ € ν•©λ‹ˆλ‹€.


🎯 TanStack Queryλž€?

TanStack Query(ꡬ React Query)λŠ” μ„œλ²„ μƒνƒœ 관리 라이브러리둜, λ‹€μŒκ³Ό 같은 핡심 κΈ°λŠ₯을 μ œκ³΅ν•©λ‹ˆλ‹€:

βœ” 데이터 페칭(Fetching) 및 캐싱 – API 데이터λ₯Ό μžλ™μœΌλ‘œ μΊμ‹±ν•˜μ—¬ λΆˆν•„μš”ν•œ λ„€νŠΈμ›Œν¬ μš”μ²­μ„ μ€„μž…λ‹ˆλ‹€.
βœ” μžλ™ κ°±μ‹ (Refetching) – 데이터가 λ³€κ²½λ˜λ©΄ μžλ™μœΌλ‘œ μ΅œμ‹  μƒνƒœλ‘œ λ™κΈ°ν™”λ©λ‹ˆλ‹€.
βœ” μ „μ—­ μƒνƒœ 동기화 – μ—¬λŸ¬ μ»΄ν¬λ„ŒνŠΈμ—μ„œ 같은 데이터λ₯Ό κ³΅μœ ν•  λ•Œ νŽΈλ¦¬ν•©λ‹ˆλ‹€.
βœ” λ‘œλ”© & μ—λŸ¬ 핸듀링 – λ‘œλ”©, 성곡, μ—λŸ¬ μƒνƒœλ₯Ό μžλ™μœΌλ‘œ κ΄€λ¦¬ν•©λ‹ˆλ‹€.

πŸ’‘ 예λ₯Ό λ“€μ–΄, λ²„νŠΌμ„ 눌러 API 데이터λ₯Ό μ—…λ°μ΄νŠΈν•  λ•Œ, useMutation을 ν™œμš©ν•˜λ©΄ κΉ”λ”ν•˜κ²Œ μ²˜λ¦¬ν•  수 μžˆμŠ΅λ‹ˆλ‹€.


πŸ› οΈ useMutation κΈ°λ³Έ μ‚¬μš©λ²•

useMutation 훅은 데이터λ₯Ό λ³€κ²½ν•˜λŠ” API μš”μ²­(POST, PUT, DELETE) 을 관리할 λ•Œ μ‚¬μš©λ©λ‹ˆλ‹€.

πŸ“Œ useMutation을 μ‚¬μš©ν•˜λŠ” 이유

  • useQueryλŠ” 데이터λ₯Ό κ°€μ Έμ˜¬ λ•Œ μ‚¬μš©ν•˜μ§€λ§Œ,
  • useMutation은 데이터λ₯Ό λ³€κ²½(μ—…λ°μ΄νŠΈ, μ‚­μ œ, μΆ”κ°€) ν•  λ•Œ μ‚¬μš©ν•©λ‹ˆλ‹€.

βœ… κΈ°λ³Έ μ½”λ“œ 예제

μ•„λž˜λŠ” useMutation을 μ‚¬μš©ν•˜μ—¬ νŠΉμ • 데이터λ₯Ό μ—…λ°μ΄νŠΈν•˜λŠ” μ˜ˆμ œμž…λ‹ˆλ‹€.

import { useMutation, useQueryClient } from "@tanstack/react-query";
import React from "react";
import { updateTestResultVisibility } from "../api/testResults";
import Button from "../components/Button";

const Example = ({ result }) => {
  const queryClient = useQueryClient();

  // βœ… useMutation을 μ‚¬μš©ν•˜μ—¬ 데이터 μ—…λ°μ΄νŠΈ
  const visibleToggleMutation = useMutation({
    mutationFn: updateTestResultVisibility, // API 호좜 ν•¨μˆ˜
    onSuccess: () => {
      // πŸ”„ μ„±κ³΅ν•˜λ©΄ μΊμ‹œλ₯Ό λ¬΄νš¨ν™”ν•˜μ—¬ μ΅œμ‹  데이터 κ°€μ Έμ˜€κΈ°
      queryClient.invalidateQueries({ queryKey: ["testResults"] });
    },
  });

  return (
    <Button
      primary="true"
      text={result.visibility ? "λΉ„κ³΅κ°œλ‘œ μ „ν™˜" : "곡개둜 μ „ν™˜"}
      onClickFunc={() =>
        visibleToggleMutation.mutate({
          id: result.id,
          visibility: !result.visibility, // ν˜„μž¬ μƒνƒœ λ°˜μ „
        })
      }
    />
  );
};

export default Example;

⚠️ λ‚΄κ°€ λ²”ν•œ μ‹€μˆ˜μ™€ μˆ˜μ • 방법

사싀 μ²˜μŒμ—λŠ” μ•„λž˜μ²˜λŸΌ mutate에 두 개의 인자λ₯Ό μ „λ‹¬ν–ˆμ—ˆμŠ΅λ‹ˆλ‹€.

// ❌ 잘λͺ»λœ μ½”λ“œ: 두 번째 μΈμžλŠ” μ˜΅μ…˜μœΌλ‘œ 인식됨
visibleToggleMutation.mutate(result.id, !result.visibility);

μ΄λ ‡κ²Œ μž‘μ„±ν•˜λ©΄ 두 번째 μΈμžκ°€ mutation의 μ˜΅μ…˜μœΌλ‘œ ν•΄μ„λ˜μ–΄ API에 μ œλŒ€λ‘œ μ „λ‹¬λ˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€.
useMutation의 mutate ν•¨μˆ˜λŠ” "ν•˜λ‚˜μ˜ κ°’λ§Œ" 받도둝 μ„€κ³„λ˜μ–΄ 있기 λ•Œλ¬Έμž…λ‹ˆλ‹€.

πŸ”₯ μ˜¬λ°”λ₯Έ μˆ˜μ • μ½”λ“œ

// βœ… μ˜¬λ°”λ₯Έ μ½”λ“œ: 객체둜 λ¬Άμ–΄μ„œ 전달
visibleToggleMutation.mutate({
  id: result.id,
  visibility: !result.visibility,
});

이제 API에 μ˜¬λ°”λ₯Έ 값이 μ „λ‹¬λ˜λ©΄μ„œ λ²„νŠΌ 클릭 μ‹œ μ¦‰μ‹œ 반영되고, μ΅œμ‹  μƒνƒœκ°€ μœ μ§€λ©λ‹ˆλ‹€. πŸŽ‰


πŸ† 정리

βœ” useMutation은 데이터λ₯Ό λ³€κ²½(μ—…λ°μ΄νŠΈ, μ‚­μ œ, μΆ”κ°€)ν•  λ•Œ μ‚¬μš©
βœ” mutate ν•¨μˆ˜λŠ” ν•˜λ‚˜μ˜ 객체λ₯Ό 전달해야 ν•œλ‹€.
βœ” onSuccessμ—μ„œ queryClient.invalidateQueries(["testResults"])λ₯Ό ν˜ΈμΆœν•˜λ©΄ 데이터가 μžλ™μœΌλ‘œ μ΅œμ‹  μƒνƒœλ‘œ κ°±μ‹ 


πŸš€ React ν”„λ‘œμ νŠΈμ—μ„œ TanStack Queryλ₯Ό 적극 ν™œμš©ν•˜λ©΄, API μƒνƒœ 관리가 λ”μš± νŽΈλ¦¬ν•΄μ§‘λ‹ˆλ‹€.
μ•žμœΌλ‘œλ„ λ‹€μ–‘ν•œ μƒν™©μ—μ„œ useMutation을 ν™œμš©ν•΄λ³΄μ„Έμš”! πŸ˜†πŸ”₯

0개의 λŒ“κΈ€