공식문서 : https://tanstack.com/query/v4/docs/guides/optimistic-updates
mutation을 수행하기 전에, state를 낙관적으로 업데이트하면 mutation이 실패할 가능성이 있다. 이러한 대부분의 실패 사례에서, 낙관적인 쿼리들에 대해 refetch를 트리거하여 실제 서버 state로 되돌릴 수 있다. 그러나 일부 상황에서는 refetch가 제대로 작동하지 않을 수 있으며 mutation 에러는 refetch를 불가능하게 하는 일종의 서버 이슈를 나타낼 수 있다. 이 경우, 대신 업데이트를 롤백하도록 선택할 수 있다.
이를 위해, useMutation
의 onMutate
핸들러 옵션을 사용하면 나중에 onError
및 onSettled
핸들러 모두에 마지막 인수로 전달될 값을 반환할 수 있다. 대부분의 경우, 롤백 함수를 전달하는것이 가장 유용하다.
const queryClient = useQueryClient()
useMutation(updateTodo, {
// When mutate is called:
onMutate: async newTodo => {
// Cancel any outgoing refetches (so they don't overwrite our optimistic update)
await queryClient.cancelQueries(['todos'])
// Snapshot the previous value
const previousTodos = queryClient.getQueryData(['todos'])
// Optimistically update to the new value
queryClient.setQueryData(['todos'], old => [...old, newTodo])
// Return a context object with the snapshotted value
return { previousTodos }
},
// If the mutation fails, use the context returned from onMutate to roll back
onError: (err, newTodo, context) => {
queryClient.setQueryData(['todos'], context.previousTodos)
},
// Always refetch after error or success:
onSettled: () => {
queryClient.invalidateQueries(['todos'])
},
})
useMutation(updateTodo, {
// When mutate is called:
onMutate: async newTodo => {
// Cancel any outgoing refetches (so they don't overwrite our optimistic update)
await queryClient.cancelQueries(['todos', newTodo.id])
// Snapshot the previous value
const previousTodo = queryClient.getQueryData(['todos', newTodo.id])
// Optimistically update to the new value
queryClient.setQueryData(['todos', newTodo.id], newTodo)
// Return a context with the previous and new todo
return { previousTodo, newTodo }
},
// If the mutation fails, use the context we returned above
onError: (err, newTodo, context) => {
queryClient.setQueryData(
['todos', context.newTodo.id],
context.previousTodo
)
},
// Always refetch after error or success:
onSettled: newTodo => {
queryClient.invalidateQueries(['todos', newTodo.id])
},
})
원하는 경우 별도의 onError
및 onSuccess
핸들러 대신 onSettled
함수를 사용할 수도 있다.
useMutation(updateTodo, {
// ...
onSettled: (newTodo, error, variables, context) => {
if (error) {
// do something
}
},
})