useMutation은 데이터의 수정, 삭제를 서버에 요청하는 메서드이다.
이 블로그 포스트의 openAPI는 요청을 보내도 데이터가 수정되거나 하지 않지만 응답값은 잘 나오니 변경된 것이라고 가정하에 작성한다.
// PostDetail.jsx
import { useQuery, useMutation } from "react-query";
async function fetchComments(postId) {
const response = await fetch(`https://jsonplaceholder.typicode.com/comments?postId=${postId}`);
return response.json();
}
async function deletePost(postId) {
const response = await fetch(`https://jsonplaceholder.typicode.com/postId/${postId}`, {
method: "DELETE",
});
return response.json();
}
async function updatePost(postId) {
const response = await fetch(`https://jsonplaceholder.typicode.com/postId/${postId}`, {
method: "PATCH",
data: { title: "REACT QUERY FOREVER!!!!" },
});
return response.json();
}
export function PostDetail({ post }) {
const { data, isLoading, isError, error } = useQuery(["fetchComments", post.id], () =>
fetchComments(post.id)
);
const deleteMutation = useMutation((postId) => deletePost(postId));
if (isLoading) return <h2>Loading...</h2>;
if (isError)
return (
<>
<h2>Error!</h2>
<p>{error.toString()}</p>
</>
);
return (
<>
<h3 style={{ color: "blue" }}>{post.title}</h3>
<button onClick={() => deleteMutation.mutate(post.id)}>Delete</button>
{deleteMutation.isError && <p style={{ color: "red" }}>Error deleting the post</p>}
{deleteMutation.isLoading && <p style={{ color: "yellow" }}>Deleting the post</p>}
{deleteMutation.isSuccess && <p style={{ color: "green" }}>Deleted the post</p>}
<button>Update title</button>
<p>{post.body}</p>
<h4>Comments</h4>
{data.map((comment) => (
<li key={comment.id}>
{comment.email}: {comment.body}
</li>
))}
</>
);
}
useMutation의 경우에는 queryKey가 필요하지 않고 바로 작동시킬 함수를 작성하면 된다. 여기서 useQuery와의 차이점이 있다.
const deleteMutation = useMutation((postId) => deletePost(postId));
useQuery는 인수(argument)로서 전달하는 쿼리 함수와는 달리 useMutation에서는 쿼리 함수 자체에서 인수를 받을 수 있다.
<button onClick={() => deleteMutation.mutate(post.id)}>Delete</button>
그래서 삭제 버튼을 누르면 실행시키는 함수에서도 post.id의 인수를 전달하면 위의 코드의 postId로 들어가게 되어 실행되는 것이다.
{deleteMutation.isError && <p style={{ color: "red" }}>Error deleting the post</p>}
{deleteMutation.isLoading && <p style={{ color: "yellow" }}>Deleting the post</p>}
{deleteMutation.isSuccess && <p style={{ color: "green" }}>Deleted the post</p>}
코드와 같이 mutation에 실패했을 경우의 isError, 진행중일 때의 isLoading, 성공했을때의 isSuccess 등의 추가적인 메서드들이 있다.
async function updatePost(postId) {
const response = await fetch(`https://jsonplaceholder.typicode.com/postId/${postId}`, {
method: "PATCH",
data: { title: "UPDATE SUCCESS" },
});
return response.json();
}
업데이트의 경우에는 메서드를 PATCH로 설정하고 data 객체 안에 title 을 변경하면된다. 예시에서는 하드코딩으로 설정했지만 input 입력값을 받은 데이터를 useState로 저장하여 설정할 수 있다.
const updateMutation = useMutation((postId) => updatePost(postId));
만약 useState를 사용한다면 updatePost함수에 두번째 인수에 넣어주고 하드코딩 된 부분을 수정해주면 변경될 것이다.
<button onClick={() => updateMutation.mutate(post.id)}>Update title</button>
{updateMutation.isError && <p style={{ color: "red" }}>Error updating the post</p>}
{updateMutation.isLoading && <p style={{ color: "yellow" }}>Updating the post</p>}
{updateMutation.isSuccess && <p style={{ color: "green" }}>Updated the post</p>}
물론 똑같이 isError, isLoading, isSuccess 객체가 있으므로 동일하게 사용이 가능하다.