본문 바로가기
리액트 궁금증

[react-query] 4. react-query의 useMutation

by 띠리에이터 2024. 6. 17.

useMutation에서 mutation은 데이터베이스에 새로운 값을 추가하거나 수정, 삭제하는 사이드 이펙트를 가진 함수를 의미한다.  따라서 사이드 이펙트가 발생하는 경우 useMutation이라는 훅을 사용.

 

useMutation과 useQuery의 차이점은 useQuery의 queryFn은 컴포넌트가 마운트 되면 자동으로 실행되지만

useMutation은 실제로 mutation하는 함수를 직접 실행해줘야한다.

mutate함수를 통해 mutationFn으로 등록했떤 함수를 실행할 수 있고 서버 데이터에 관여할 수 있다. 

 

muatate()를 하면 데이터는 변경이 되지만 캐시에 저장된 데이터는 refetch를 하지 않는 이상 기존의 데이터가 그대로 저장되기 때문에 refetch를 해줘야만 변경된 데이터를 화면에 제대로 반영할 수 있다. 

 

1.useMutation post

 

mutation과  post를 사용한 업로드 추가 기능을 만들어보자

 

일단 api.js파일에 포스트를 추가하는 api요청 함수를 만들고

api.js

export async function uploadPost(newPost) {
  const response = await fetch(`${BASE_URL}/posts`, {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
    },
    body: JSON.stringify(newPost),
  });

  if (!response.ok) {
    throw new Error("Failed to upload the post.");
  }

  return await response.json();
}

 

 

home.js에 간단한 폼 기능과 useMutation을 사용한 함수를 만들자 

const Home = () => {
  const { data: postresult } = useQuery({
    queryKey: ["getpost"],
    queryFn: getPosts,
  });

  const username = "codeit";
  const [content, setContent] = useState("");

  const { mutate: uploadPostMutation } = useMutation({
    mutationKey: ["uploadpost"],
    mutationFn: (newPost) => uploadPost(newPost),
  });

  const handleInputChange = (e) => {
    setContent(e.target.value);
  };

  const handleSubmit = (e) => {
    e.preventDefault();
    const newPost = { username, content };
    uploadPostMutation(newPost);
  };

  const posts = postresult?.results ?? [];
  console.log(posts);

  return (
    <>
      <div>
        <form onSubmit={handleSubmit}>
          <textarea
            name="content"
            value={content}
            onChange={handleInputChange}
          />
          <button disabled={!content} type="submit">
            업로드
          </button>
        </form>
      </div>
      <div>
        <ul>
          {posts.map((post) => (
            <li key={post.id}>
              {post.user.name}: {post.content}
            </li>
          ))}
        </ul>
      </div>
    </>
  );
};

export default Home;

 

mutate 함수로서 uploadPost에 newPost를 담아서 전송해주면

 post요청이 성공적으로 되는 것을 확인할 수 있다. 

하지만 mutate함수를 실행한다고 해서 캐시에 있는 데이터가 자동으로 변경되는 것이 아니어서 데이터를 refetch해줘야 하는데 항상 새로고침 하는 것보다는 자동으로 refetch가 되도록 만들 수 있다. 

쿼리클라이언트의 invalidateQueries()라는 함수를 사용하면 업로드가 끝난 이후 자동으로 refetch하도록 설정할 수 있다. 

 

invalidateQueries()는 캐시에 있는 모든 쿼리 또는 특정 쿼리들을 invalidate하는 함수이다. 

쿼리를 invalidate하면 해당 쿼리를 통해 받아 온 데이터를 staleTime이 지났는지 아닌지에 상관없이 무조건 stale상태로 만들고 해당 데이터를 refetch시켜준다. 

import { useMutation, useQuery,useQueryClient } from "@tanstack/react-query";

const Home = ()=>{
const queryClient = useQueryClient();

// ...

const uploadPostMutation = useMutation({
  mutationFn: (newPost) => uploadPost(newPost),
  onSuccess: () => {
    queryClient.invalidateQueries({ queryKey: ['posts'] });
  },
});

return(
//....
)
}

 

useQueryClient훅을 import 해준 다음에 mutation이 성공한 시점에 queryClient.invalidateQueries({refetch 할 queryKey)}

를 설정해주면  mutation성공 후 해당 queryKey가 자동으로 refetch가 되기 때문에 화면에서 데이터가 갱신된다. 

 

useMutation함수의 콜백옵션에서 성공한 시점인 onSuccess뿐만 아니라 onError, onMutate 등에도 적용이 가능하다.