Optimistic Update
Optimistic Update
낙관적 업데이트
서버에서 상태가 변경되고 사용자에게 보여질 때, 즉각적인 피드백을 제공해야 하는 경우 사용한다.
성공 여부가 크게 중요하지 않으면서, 서버에서의 처리 속도가 오래 걸리면서, 사용자에게 빠른 피드백이 중요한 경우에 사용한다
- ex) 좋아요 누르기
Tanstack Query에서 Optimistic Update 예제 코드 제공
useMutation({
mutationFn: updateTodo,
// When mutate is called:
onMutate: async (newTodo) => {
// Cancel any outgoing refetches
// (so they don't overwrite our optimistic update)
await queryClient.cancelQueries({ queryKey: ['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({ queryKey: ['todos', newTodo.id] })
},
})
onMutate
cancelQueries를 하는 이유
- refetch가 발생할 경우, 현재 optimistic update의 변경 사항을 overwrite할 수 있음.
- 결과적으로 optimistic update가 무의미해지게 됨.
- 그래서 요청중인 쿼리가 있다면 취소
- 동시성 제어, lock을 거는 느낌
- ( getQueryData는 refetch가 포함되지 X, 그냥 캐시에서 값만 즉시 반환 )
- 다른 예시로 useQuery훅으로 키, api 호출 함수를 주고 접근하려 하면 refetch 포함되어버림.
- 이후, 보내려는 값을 포함해서 쿼리 캐시의 상태를 조작함.
onError
- 실행 시 fallback
- 조작했던 값 rollback
onSettled : 실패, 성공 여부와 관계없이 실행됨
- 완료시 invalidateQueries를 통해 쿼리 캐시 상태 초기화
- 이 부분을 호출하는 이유는 업데이트를 실패했든, 성공했든 다른 클라이언트에 의해 서버 데이터의 변화가 생길 수 있는데 이 부분들을 감지하고 데이터를 갱신해주기 위함이다.