← 전체 글로 돌아가기

Next.js

React 낙관적 업데이트를 되돌릴 때 원본 상태를 보존한 짧은 튜토리얼

좋아요 API가 실패해도 정확히 이전 화면으로 돌아가도록 만든 구현을 정리했다

빠른 화면이 오히려 어색해진 순간

좋아요 버튼을 누르면 서버 응답 뒤 숫자를 바꾸도록 처음 구현했다. 느린 모바일에서 클릭이 먹지 않은 것처럼 보여 낙관적 업데이트를 적용했지만, 실패 때 현재 숫자에서 하나 빼는 방식은 여러 번 클릭하면 틀어졌다.

변경 전 스냅샷을 저장했다

요청 시작 순간의 상태를 복사하고 성공하면 서버 응답을 확정값으로 쓴다. 실패하면 계산하지 않고 스냅샷을 복원한다.

async function toggleLike() {
  const previous = { liked, count }
  setLiked(!liked)
  setCount(count + (liked ? -1 : 1))
  try {
    const result = await fetch('/api/like', { method: 'POST' })
    if (!result.ok) throw new Error('like request failed')
    const serverState = await result.json()
    setLiked(serverState.liked)
    setCount(serverState.count)
  } catch {
    setLiked(previous.liked)
    setCount(previous.count)
    setError('저장하지 못했습니다. 잠시 후 다시 시도해 주세요.')
  }
}

중복 요청을 막기 위해 pending 동안 버튼을 비활성화했다. 요청 순서가 뒤섞이는 UI라면 요청 ID나 서버 버전도 필요하다.

놓쳤던 테스트

성공만 테스트한 뒤 실패를 재현했다. 첫 요청을 지연 후 실패시키기, 실패 메시지 중 재클릭하기, 서버가 예상과 다른 count를 반환하기를 확인했다. 기준은 원래 값이 아니라 실패 직전 스냅샷과 일치하는가였다.

적용 전 점검

  • 롤백에 현재 상태를 계산해 쓰지 않는다.
  • 성공 시 서버 응답을 최종 기준으로 삼는다.
  • 중복 클릭과 순서 뒤바뀜을 처리한다.
  • 실패 사실을 사용자에게 알린다.

화면을 빠르게 만드는 것보다 실패했을 때 믿을 만하게 돌아오는 것이 더 중요한 기준이었다.