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를 통해 쿼리 캐시 상태 초기화
  • 이 부분을 호출하는 이유는 업데이트를 실패했든, 성공했든 다른 클라이언트에 의해 서버 데이터의 변화가 생길 수 있는데 이 부분들을 감지하고 데이터를 갱신해주기 위함이다.