안녕하세여 오늘은 서버 상태데이터를 업데이트, 삭제해주는 useMutation을 배워보겠습니다.╰(°▽°)╯
useMutation 이해하기
mutate 이해하기
useMutation은 useQuery로 정의한 데이터를
update,delete
해주는 리액트 쿼리 훅입니다.
기본적으로 useQuery와 비슷하지만 query key가 안들어 간다는 차이점이 있습니다.
const { data, isLoading, mutate, mutateAsync } = useMutation(mutationFn, options);
첫번쨰 인자엔 업데이트 될떄 반응 할 비동기함수
두번쨰 인자엔 옵션
이 들어갑니다.
useMutation에서 가장 많이 쓰는 3가지 옵션이 있습니다.
사용자에게 바로바로 보여야하는 간단한 서버요청이 있습니다.
하지만 데이터응답을 받을떄까지 약간의 딜레이가 있는데 그 딜레이를 없애기위해
더미로 만든 성공한 데이터를 응답을 받기전에 미리 사용자에게 보여주는것을 낙관적 업데이트라고 합니다.
그후 정말 응답이 온다면 값을 바꿔줍니다.
미리 성공했다치고 응답받기전부터 성공한 데이터를 사용자에게 보여준다는 건데
만약 실패하면 어떻게 되나요?
=> 실패했다면 유감입니다.
=> 그렇기떄문에 낙관적 업데이트는 웬만하면 성공 할 서버요청이며 사용자에게 바로바로 보여야 되는 요청만 잘 생각해서 낙관적 업데이트를 시도해야합니다.
invalidateQueries는 useQuery에서 사용되는 queryKey의 캐시 데이터를 제거해줍니다.
그렇게 되면 캐시가 없기떄문에 staleTiem,cashTime을 무시하고 무조건 새로운 데이터
를 가져올 수 있게 됩니다.
const updateMutation = useMutation(() => updatePost(post.id),{
onSuccess: () => { // 요청이 성공한 경우
console.log('onSuccess');
queryClient.invalidateQueries('getCommnet'); // queryKey 유효성 제거
},
});
invalidateQueries는 해당 queryKey의 캐시를 제거해서 새로운 데이터를 가져오는 반면에
setQueryData는 queryKey를 제거하지않지만 그냥 바로 새로운 데이터를 fetching해옵니다.
결론적으로 새로운 fetching데이터를 가져온다는 점은 같아서 둘중 하나를 선택해서 쓰면 될것같습니다.
저는 개인적으로 invalidateQueries 쓰겠습니다!
// useMutation
const {
data,
error,
isError,
isIdle,
isLoading,
isPaused,
isSuccess,
mutate,
mutateAsync,
reset,
status,
} = useMutation(mutationFn, {
cacheTime,
mutationKey,
networkMode,
onError, // onError는 에러가 발생될 경우 실행되는 구간입니다.
onMutate,
onSettled, // onSettled는 finally 구문처럼 요청이 성공하든 에러가 발생되든 상관없이 마지막에 실행되는 구간입니다.
onSuccess, // onSuccess는 요청이 성공되었을 때 실행되는 구간입니다.
retry,
retryDelay,
useErrorBoundary,
meta
})
// mutate함수
mutate(variables, {
onError,
onSettled,
onSuccess,
})
const deleteMutation = useMutation((postId) => deletePost(postId));
<button
onClick={() => {
deleteMutation.mutate(post.id);
}}
>
useMutation을 선언한 deleteMutation안에 mutate라는 속성이 있는데
mutate는 useMutation을 조작할 수 있는 속성
입니다 mutate안에는 useMutation의 비동기 함수에 들어갈 인자
가 들어갑니다.
import { useMutation, useQuery } from "@tanstack/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 }) {
// replace with useQuery
const { data, isLoading, isError } = useQuery(["getCommnet", post.id], () =>
fetchComments(post.id)
);
const deleteMutation = useMutation((postId) => deletePost(postId)); //인수전달가능
const updateMutation = useMutation(() => updatePost(post.id));
if (isError) {
return "An error occurred";
}
return (
<>
{updateMutation.isLoading ? <p>updating data</p> : ""}
{updateMutation.isSuccess ? <p>update finish!</p> : ""}
{updateMutation.isError ? <p>updateError data</p> : ""}
<h3 style={{ color: "blue" }}>{post.title}</h3>
<button
onClick={() => {
deleteMutation.mutate(post.id);
}}
>
Delete
</button>
{deleteMutation.isError && <p>Error deleting the post</p>}
{deleteMutation.isLoading && <p>deleting the post</p>}
{deleteMutation.isSuccess && <p>Post has been deleted</p>}
<button onClick={() => updateMutation.mutate(post.id)}>
Update title
</button>
<p>{post.body}</p>
<h4>Comments</h4>
{isLoading ? (
<div>로딩중입니다...</div>
) : (
data?.map((comment) => (
<li key={comment.id}>
{comment.email}: {comment.body}
</li>
))
)}
</>
);
}
useMutation 와 useMutation을 조작할 수 있는 mutate를 알아보았습니다!╰(°▽°)╯