Front-end/React

[React] Mutation: ๋ฐ์ดํ„ฐ์˜ ๋น„๋ฐ€ ์ž‘์—…์‹ค ๐Ÿ› ๏ธ

xeunnie 2025. 1. 9. 01:00
728x90
๋ฐ˜์‘ํ˜•

Mutation ํ†บ์•„๋ณด๊ธฐ! ๐Ÿ› ๏ธ

Mutation์€ ๋ฐ์ดํ„ฐ์˜ ์ƒํƒœ๋ฅผ ๋ฐ”๊พธ๋Š” ์ž‘์—…์„ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค. ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์˜ ์ •๋ณด๋ฅผ ์ˆ˜์ •ํ•˜๊ฑฐ๋‚˜ ์ถ”๊ฐ€, ์‚ญ์ œํ•˜๋Š” ๋ชจ๋“  ํ–‰๋™์ด ์—ฌ๊ธฐ์— ์†ํ•˜์ฃ . GraphQL, React Query ๊ฐ™์€ ๊ณณ์—์„œ๋„ mutation์€ ์ค‘์š”ํ•œ ๊ฐœ๋…์ด์—์š”. ์˜ค๋Š˜์€ ์ด mutation์ด๋ผ๋Š” ์•™์ฆ๋งž์€ ๋…€์„์„ ํŒŒํ—ค์ณ ๋ณผ ๊ฑฐ์˜ˆ์š”. ์ค€๋น„๋๋‚˜์š”? ๐Ÿ˜„


๐Ÿ” Mutation์ด๋ž€?

Mutation์€ ๋ฐ์ดํ„ฐ๋ฅผ ๋ณ€๊ฒฝํ•˜๊ธฐ ์œ„ํ•œ ์ž‘์—…์ด์—์š”.

์—ฌ๊ธฐ์„œ ๋ณ€๊ฒฝ์ด๋ž€:

  • ์ƒˆ๋กœ์šด ๋ฐ์ดํ„ฐ๋ฅผ ์ถ”๊ฐ€ํ•˜๊ธฐ
  • ๊ธฐ์กด ๋ฐ์ดํ„ฐ๋ฅผ ์ˆ˜์ •ํ•˜๊ธฐ
  • ๋ฐ์ดํ„ฐ๋ฅผ ์‚ญ์ œํ•˜๊ธฐ

์ผ๋ฐ˜์ ์œผ๋กœ REST API์˜ POST, PUT, DELETE์™€ ๋Œ€์‘๋˜๋ฉฐ, GraphQL์—์„  mutation์ด๋ผ๋Š” ํ‚ค์›Œ๋“œ๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ๋‹ค๋ฃน๋‹ˆ๋‹ค.


๐ŸŒ Mutation์˜ ์„ธ๊ณ„ ํƒํ—˜

RESTful API์—์„œ์˜ Mutation ๐Ÿงฉ

REST API์—์„œ mutation์€ ํ”ํžˆ CRUD(Create, Read, Update, Delete) ์ž‘์—… ์ค‘ Create, Update, Delete์— ํ•ด๋‹นํ•ด์š”.

 

์˜ˆ์ œ: ์‚ฌ์šฉ์ž ์ถ”๊ฐ€

fetch('https://api.example.com/users', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({ name: 'Alice', age: 25 }),
});

 

์˜ˆ์ œ: ์‚ฌ์šฉ์ž ์ •๋ณด ์ˆ˜์ •

fetch('https://api.example.com/users/1', {
  method: 'PUT',
  headers: {
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({ age: 26 }),
});

 

์˜ˆ์ œ: ์‚ฌ์šฉ์ž ์‚ญ์ œ

fetch('https://api.example.com/users/1', {
  method: 'DELETE',
});

 

GraphQL์—์„œ์˜ Mutation ๐Ÿงฉ

GraphQL์—์„œ๋Š” query๋Š” ๋ฐ์ดํ„ฐ๋ฅผ ์ฝ๊ณ , mutation์€ ๋ฐ์ดํ„ฐ๋ฅผ ๋ณ€๊ฒฝํ•ฉ๋‹ˆ๋‹ค.

 

์˜ˆ์ œ: ์‚ฌ์šฉ์ž ์ถ”๊ฐ€

mutation {
  addUser(name: "Alice", age: 25) {
    id
    name
    age
  }
}

 

์˜ˆ์ œ: ์‚ฌ์šฉ์ž ์ •๋ณด ์ˆ˜์ •

mutation {
  updateUser(id: 1, age: 26) {
    id
    name
    age
  }
}

 

์˜ˆ์ œ: ์‚ฌ์šฉ์ž ์‚ญ์ œ

mutation {
  deleteUser(id: 1) {
    success
  }
}

 

GraphQL์—์„œ๋Š” mutation์ด ์„œ๋ฒ„์—์„œ ์ƒํƒœ๋ฅผ ๋ณ€๊ฒฝํ•˜๊ณ , ๋ณ€๊ฒฝ๋œ ๋ฐ์ดํ„ฐ๋ฅผ ๋ฐ˜ํ™˜ํ•  ์ˆ˜๋„ ์žˆ์–ด์š”. (REST API์™€ ๋‹ค๋ฅธ ์ค‘์š”ํ•œ ํŠน์ง•!)


๐Ÿ’ซ Mutation๊ณผ React Query: ๋ฐ์ดํ„ฐ ๋ณ€๊ฒฝ์˜ ์—ฐ๊ธˆ์ˆ ์‚ฌ

React Query์—์„œ mutation์€ ์„œ๋ฒ„ ๋ฐ์ดํ„ฐ๋ฅผ ๋ณ€๊ฒฝํ•˜๊ธฐ ์œ„ํ•œ ๋„๊ตฌ์˜ˆ์š”.

์˜ˆ๋ฅผ ๋“ค์–ด, ๋ฐ์ดํ„ฐ๋ฅผ ์ถ”๊ฐ€, ์ˆ˜์ •, ์‚ญ์ œํ•  ๋•Œ ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค.

React Query๋กœ Mutation ์„ค์ •ํ•˜๊ธฐ ๐Ÿ› ๏ธ

1๏ธโƒฃ useMutation ํ›… ์‚ฌ์šฉํ•˜๊ธฐ

React Query๋Š” useMutation์„ ํ†ตํ•ด mutation์„ ๊ด€๋ฆฌํ•ฉ๋‹ˆ๋‹ค.

import { useMutation } from 'react-query';
import axios from 'axios';

function addUser(userData) {
  return axios.post('/users', userData);
}

function App() {
  const mutation = useMutation(addUser);

  const handleAddUser = () => {
    mutation.mutate({ name: 'Alice', age: 25 });
  };

  return (
    <div>
      <button onClick={handleAddUser}>Add User</button>
      {mutation.isLoading && <p>Loading...</p>}
      {mutation.isError && <p>Error: {mutation.error.message}</p>}
      {mutation.isSuccess && <p>User added successfully!</p>}
    </div>
  );
}

 

2๏ธโƒฃ onSuccess์™€ onError ์ฒ˜๋ฆฌ

React Query๋Š” mutation ๊ฒฐ๊ณผ๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ ํ›„์† ์ž‘์—…์„ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ์–ด์š”.

const mutation = useMutation(addUser, {
  onSuccess: () => {
    console.log('User added successfully!');
  },
  onError: (error) => {
    console.error('Error adding user:', error);
  },
});

๐Ÿ Mutation์˜ ์žฅ์ 

  1. ๋ช…ํ™•ํ•œ ์ž‘์—… ๊ตฌ๋ถ„: ๋ฐ์ดํ„ฐ๋ฅผ ์ˆ˜์ •ํ•˜๋Š” ์ž‘์—…์„ ๋ช…ํ™•ํ•˜๊ฒŒ ๊ตฌ๋ถ„ํ•ด์ค๋‹ˆ๋‹ค.
  2. API ์‘๋‹ต ์ฒ˜๋ฆฌ: ์„œ๋ฒ„์˜ ์‘๋‹ต์— ๋”ฐ๋ผ ์„ฑ๊ณต/์‹คํŒจ๋ฅผ ํšจ์œจ์ ์œผ๋กœ ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ์–ด์š”.
  3. ์žฌ์‚ฌ์šฉ์„ฑ: React Query, GraphQL ๋“ฑ์˜ ํˆด์„ ์‚ฌ์šฉํ•˜๋ฉด, mutation ๋กœ์ง์„ ์žฌ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์–ด์š”.

โš ๏ธ Mutation ์‚ฌ์šฉ ์‹œ ์ฃผ์˜์ 

1๏ธโƒฃ ๋ถˆ๋ณ€์„ฑ ์œ ์ง€

์ƒํƒœ ๊ด€๋ฆฌ์—์„œ ๋ฐ์ดํ„ฐ๋ฅผ ๋ณ€๊ฒฝํ•  ๋•Œ๋Š” ์›๋ณธ์„ ์ˆ˜์ •ํ•˜์ง€ ์•Š๊ณ  ์ƒˆ๋กœ์šด ๊ฐ์ฒด๋ฅผ ๋งŒ๋“ค์–ด์•ผ ํ•ด์š”.

const newData = { ...data, age: 26 }; // ๋ถˆ๋ณ€์„ฑ ์œ ์ง€

 

2๏ธโƒฃ ์—๋Ÿฌ ํ•ธ๋“ค๋ง

mutation์€ ์‹คํŒจํ•  ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์—, ์ ์ ˆํ•œ ์—๋Ÿฌ ์ฒ˜๋ฆฌ๊ฐ€ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.

 

3๏ธโƒฃ ์บ์‹ฑ

๋ฐ์ดํ„ฐ๋ฅผ ์ˆ˜์ •ํ•œ ํ›„์—๋Š” React Query ๋“ฑ์˜ ์บ์‹œ๋ฅผ ์—…๋ฐ์ดํŠธํ•ด UI์™€ ์„œ๋ฒ„ ์ƒํƒœ๋ฅผ ๋™๊ธฐํ™”ํ•ด์•ผ ํ•ด์š”.


๐Ÿ’ผ ์‹ค๋ฌด์—์„œ์˜ ์˜ˆ์ œ: ์‚ฌ์šฉ์ž ๊ด€๋ฆฌ

์•„๋ž˜ ์˜ˆ์ œ๋Š” React Query์™€ useMutation์„ ์‚ฌ์šฉํ•ด ์‚ฌ์šฉ์ž๋ฅผ ์ถ”๊ฐ€, ์ˆ˜์ •, ์‚ญ์ œํ•˜๋Š” ์‹ค๋ฌด ์˜ˆ์ œ์ž…๋‹ˆ๋‹ค.

import { useMutation, useQueryClient } from 'react-query';
import axios from 'axios';

function App() {
  const queryClient = useQueryClient();
  
  const addUser = useMutation((newUser) => axios.post('/users', newUser), {
    onSuccess: () => {
      queryClient.invalidateQueries('users'); // ์บ์‹œ ์—…๋ฐ์ดํŠธ
    },
  });

  const deleteUser = useMutation((id) => axios.delete(`/users/${id}`), {
    onSuccess: () => {
      queryClient.invalidateQueries('users');
    },
  });

  const handleAddUser = () => {
    addUser.mutate({ name: 'Bob', age: 30 });
  };

  const handleDeleteUser = (id) => {
    deleteUser.mutate(id);
  };

  return (
    <div>
      <button onClick={handleAddUser}>Add User</button>
      <button onClick={() => handleDeleteUser(1)}>Delete User</button>
    </div>
  );
}

๐Ÿ”– ๊ฒฐ๋ก 

 

Mutation์€ ์„œ๋ฒ„ ๋ฐ์ดํ„ฐ์™€ UI๋ฅผ ๋™๊ธฐํ™”ํ•˜๋Š” ๋ฐ ํ•„์ˆ˜์ ์ธ ๊ฐœ๋…์ด์—์š”.

GraphQL, React Query์™€ ํ•จ๊ป˜ ์‚ฌ์šฉํ•˜๋ฉด ๋ฐ์ดํ„ฐ ๋ณ€๊ฒฝ ์ž‘์—…์„ ๋”์šฑ ๊ฐ•๋ ฅํ•˜๊ณ  ๊น”๋”ํ•˜๊ฒŒ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๋‹ต๋‹ˆ๋‹ค.

 

๐ŸŒท์ „์„ค์˜ ๊ฐœ๋ฐœ์ž๊ฐ€ ๋˜์–ด๋ด…์‹œ๋‹น!๐ŸŒท

728x90
๋ฐ˜์‘ํ˜•