
useMutation 콜백으로 데이터 바로 업데이트 하기invalidateQueries()쿼리 클라이언트의 invalidateQueries() 함수를 사용하면, 업로드가 끝난 이후에 자동으로 refetch를 하도록 설정할 수 있다.
invalidateQueries()는 말 그대로, 캐시에 있는 모든 쿼리 혹은 특정 쿼리들을 invalidate하는 함수로, 캐시에 저장된 쿼리를 무효화시킨다.
쿼리를 invalidate하면 해당 쿼리를 통해 받아온 데이터를 stale time의 경과 여부와 관계없이 무조건 stale 상태로 만들고, 해당 데이터를 백그라운드에서 refetch 하게 된다.
쿼리 클라이언트는 useQueryClient() 훅을 사용해서 가져올 수 있으며, 원하는 시점에 queryClient.invalidateQueries() 함수를 실행하면 된다.
import { useQueryClient } from '@tanstack/react-query'
const queryClient = useQueryClient();
// ...
queryClient.invalidateQueries();
useMutation() 함수의 콜백 옵션그렇다면, 언제 쿼리를 invalidate 해야할까?
mutation 객체에는 onMutate, onSuccess, onError, onSettled와 같은 주요 옵션들이 있어서, mutation cycle에 따라 적절한 동작을 추가할 수 있다.
포스트를 등록했을 때 자동으로 refetch가 되게 만들고 싶다면, onSuccess, 즉 mutation이 성공한 시점에 ['post'] 쿼리를 invalidate 해주는 함수를 콜백으로 등록해주면 되는 것이다.
const queryClient = useQueryClient();
// ...
const uploadPostMutation = useMutation({
mutationFn: (newPost) => uploadPost(newPost),
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: ['posts'] });
},
});
mutate() 함수의 콜백 옵션onSuccess, onError, onSettled와 같은 옵션은 useMutation()에서도 사용할 수 있고 mutate() 함수에서도 사용할 수 있다.
이 때, useMutation()에 등록한 콜백 함수들이 먼저 실행되고, 그 다음에 mutate()에 등록한 콜백 함수들이 실행된다.
const uploadPostMutation = useMutation({
mutationFn: (newPost) => uploadPost(newPost),
onSuccess: () => {
console.log('onSuccess in useMutation');
},
onSettled: () => {
console.log('onSettled in useMutation');
},
});
...
uploadPostMutation.mutate(newPost, {
onSuccess: () => {
console.log('onSuccess in mutate');
},
onSettled: () => {
console.log('onSettled in mutate');
},
});
한 가지 주의할 점은, useMutation()에 등록된 콜백 함수들은 컴포넌트가 언마운트되더라도 실행이 되지만, mutate()의 콜백 함수들은 만약 mutation이 끝나기 전에 해당 컴포넌트가 언마운트되면 실행되지 않는다는 것이다.
따라서, query invalidation과 같이 mutation 과정에서 꼭 필요한 로직은 useMutation()을 통해 등록하고, 그 외 다른 페이지로 리다이렉트 하거나, 결과를 토스트로 띄워주는 것과 같이 해당 컴포넌트에 종속적인 로직은 mutate()를 통해 등록해주면 된다.
...
const uploadPostMutation = useMutation({
mutationFn: (newPost) => uploadPost(newPost),
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: ['posts'] });
},
});
const handleUploadPost = (newPost) => {
uploadPostMutation.mutate(newPost, {
onSuccess: () => {
toast('포스트가 성공적으로 업로드 되었습니다!');
},
});
};
isPending 프로퍼티 활용하기포스트가 업로드되는 동안에는 버튼을 비활성화 하고자 한다면, mutation의 isPending 값을 활용하면 된다.
const uploadPostMutation = useMutation({
mutationFn: (newPost) => uploadPost(newPost),
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: ['posts'] });
},
});
// ...
<button
disabled={uploadPostMutation.isPending || !content}
type='submit'
>
업로드
</button>