mutations
은 부과 효과(side effect) 함수 입니다.
react query로 서버 상태를 관리하기 때문에 mutations
은 서버에 부가 효과를 일으킬 수 있습니다.
useMutation
은 useQuery
가 쿼리에 대해 수행하는 것처럼 mutation
의 상태를 추적합니다.
loading
, error
, status fields
를 제공하여 무슨 상태인지 알 수 있습니다.
대부분의 쿼리는 자동으로 실행됩니다.
mutations
의 경우 자동으로 실행되지 않습니다.mutations
가 useQuery
처럼 상태를 공유하지 않습니다.useQuery
를 여러 번 호출 할 수 있으며 캐시된 결과를 동일하게 반환하지만 mutations
은 동작하지 않습니다.mutation
은 대부분 쿼리에 직접 연결되지 않게 설계합니다.
mutation
이 쿼리에 대한 변경 사항을 반영하기 위해 두 가지 방법이 있습니다.
화면을 최신 상태로 만드는 가장 간단한 방법입니다.
react query가 현재 사용 중인 경우 해당 데이터를 다시 가져오며, 가져오기가 완료되면 화면이 자동으로 업데이트 됩니다.
➡ 무효화할 쿼리만 라이브러리에 알려주면 됩니다.
💡
queryClient.invalidateQueries(queryKey)
를 통해 캐시를 무효화 할 수 있습니다.
const useUpdatePostMutation = (postId: number) => {
const queryClient = useQueryClient();
return useMutation({
mutationFn: ({
postId,
title,
body,
}: {
postId: number;
title: string;
body: string;
}) => {
return updatePostDetailApi(postId, title, body);
},
onSuccess: (newPost) => {
// ✅ refetch the comments list for our blog post
queryClient.invalidateQueries(queries.posts.detail(postId).queryKey);
},
});
};
mutation
가 알아야 할 모든 정보를 반환하는 경우 데이터를 다시 검색할 필요가 없습니다.
💡
setQueryData
를 통해 직접 쿼리 캐시를 업데이트 할 수 있습니다.
const useUpdatePostMutation = (postId: number) => {
const queryClient = useQueryClient();
return useMutation({
mutationFn: ({
postId,
title,
body,
}: {
postId: number;
title: string;
body: string;
}) => {
return updatePostDetailApi(postId, title, body);
},
onSuccess: (newPost) => {
// ✅ update detail view directly
queryClient.setQueryData(queries.posts.detail(postId).queryKey, newPost);
},
});
};
setQueryData
를 통해 직접 캐시에 데이터를 주입하면 데이터가 백엔드에서 반환된 것 처럼 동작합니다.
➡ 해당 쿼리를 사용하는 모든 컴포넌트가 다시 렌더링되는 것을 뜻합니다.
🤟 대부분 무효가 선호되는 것이 안전한 접근법 이라고 생각합니다.
useQuery
캐시는 쿼리 간 전환 시, prefetching
과 결합할 때 데이터를 즉시 제공합니다.
➡ 전체적인 UI가 매우 빠르게 느껴집니다.
mutations
도 같은 이 점을 어떻게 얻을 수 있을까요?
낙관적인 업데이트는 서버에 전송하기도 전에
mutations
의 성공을 가장합니다.
1. 성공적인 응답을 받음
2. 실제 데이터를 보기 위해 무효화 처리
3. 요청이 실패하면 UI를 변환 전 상태로 롤백 처리
구체적인 예시는 공식 문서에 정리되어 있습니다. ( typescript example )
낙관적 업데이트는 정말 필요할 때 사용해 주세요
➡ UX를 실제로 나쁘게 만들 수 있으며, 로딩 애니메이션을 보여주는 것이 더 효율적일 수 있습니다.
확실하지 않을 수 있는 mutations
을 사용할 때 몇 가지 좋은 사항에 대해서 알아봅시다.
mutation
콜백에서 반환된 Promise는 react query에 의해 대기(awaited)되며, 실제로 invalidateQueries
는 Promise를 반환합니다.
➡ 관련 쿼리가 업데이트되는 동안 변환을 loading
상태로 유지하려면 콜백에서 invalidateQueries
의 결과를 반환해야 합니다.
{
// 🎉 will wait for query invalidation to finish
onSuccess: () => {
return queryClient.invalidateQueries(['posts', id, 'comments'])
}
}
{
// 🚀 fire and forget - will not wait
onSuccess: () => {
queryClient.invalidateQueries(['posts', id, 'comments'])
}
}
mutate
는 아무것도 반환하지 않습니다.mutateAsync
는 돌연변이의 결과를 포함하는 Promise를 반환합니다.
mutation reponse
에 대한 접근이 필요할 때mutateAsync
를 사용 할 수 있습니다.
mutate
을 해야한다고 생각합니다! 왜?mutate
는 콜백을 통해 데이터나 오류에 액세스할 수 있으며 오류 처리 걱정이 없음mutate
를 사용할 때 오류 처리가 필요 없습니다. 🤟mutateAsync
는 Promise를 제어할 수 있기 때문에 오류를 직접 처리해야함mutations
를 동시에 시작하며, 모든 mutations
이 끝나기를 기다리는 작업mutations
이 있는 경우 필요함반환하는 마지막 인수가 옵션 객체이므로 useMutation
은 현재 변수에 대해 하나의 인수만 사!
용할 수 있습니다.
➡ 제한적이지만, 객체를 사용하여 쉽게 해결
// 🚨 this is invalid syntax and will NOT work
const mutation = useMutation((title, body) => updateTodo(title, body))
mutation.mutate('hello', 'world')
// ✅ use an object for multiple variables
const mutation = useMutation(({ title, body }) => updateTodo(title, body))
mutation.mutate({ title: 'hello', body: 'world' })
useMutation
에 대한 콜백뿐만 아닌 mutate
에 대한 콜백을 가질 수 있습니다.
➡ mutate
의 콜백 전에 useMutation
이 호출되는 것을 알아야 합니다.
🚨 변환이 완료되기 전에 컴포넌트가 마운트 해제 된 경우 mutate
콜백이 전혀 실행되지 않을 수 있습니다.
➡ 콜백에서 문제를 분리하는 것이 좋다고 생각합니다.
useMutation
콜백 수행
절대적으로 필요한 작업 및 로직 관련 작업(쿼리 무효화)
➡ 무효화 논리는 항상 동일하기 때문에 Custom hook의 재사용성이 높습니다.
리디렉션, 토스트 알림을 콜백으로 표시하는 것과 같은 UI관련 작업을 수행
➡ 사용자가 변환이 완료되기 전에 현재 화면에서 멀리 탐색한 경우, 의도적으로 작동하지 않음
const useUpdateTodo = () =>
useMutation(updateTodo, {
// ✅ always invalidate the todo list
onSuccess: () => {
queryClient.invalidateQueries(['todos', 'list'])
},
})
// in the component
const updateTodo = useUpdateTodo()
updateTodo.mutate(
{ title: 'newTitle' },
// ✅ only redirect if we're still on the detail page
// when the mutation finishes
{ onSuccess: () => history.push('/todos') }
)
참조 링크