좋아요 버튼의 마법

382025년 09월 22일3

useOptimistic 훅의 아이디어는 구체적인 코드로 구현되기 시작했다. 팀의 목표는 복잡한 낙관적 업데이트 로직을, React 개발자에게 익숙한 훅(Hook)의 형태로 단순하게 풀어내는 것이었다.

며칠 후, 조쉬 스토리가 useOptimistic 훅을 적용한 ‘좋아요’ 버튼의 첫 번째 데모 버전을 선보였다.

// LikeButton.js 
function LikeButton({ initialLikes, postId }) {
  const [likes, setLikes] = useState(initialLikes);

  // 1. useOptimistic 훅 사용
  const [optimisticLikes, addOptimisticLike] = useOptimistic(
    likes, // 실제 상태(state)를 기반으로
    (currentLikes, newLike) => currentLikes + newLike // 낙관적 업데이트 함수
  );

  const handleLike = async () => {
    // 2. 먼저 낙관적으로 UI를 업데이트
    addOptimisticLike(1);

    // 3. 백그라운드에서 실제 서버 액션 실행
    const result = await likePost(postId);

    // 4. 만약 실패했다면? React가 알아서 롤백한다.
    if (!result.success) {
      // 롤백 로직은 useOptimistic에 내장됨
    } else {
      // 성공했다면 실제 상태를 업데이트 (선택적)
      setLikes(result.newLikes);
    }
  };

  return (
    <button onClick={handleLike}>
      ♡ {optimisticLikes}
    </button>
  );
}

코드를 본 팀원들은 감탄했다. 복잡할 것이라 예상했던 로직이 놀랍도록 직관적이었다.

useOptimistic 훅은 두 개의 값을 반환했다. 하나는 화면에 즉시 표시될 ‘낙관적 상태’인 optimisticLikes였고, 다른 하나는 그 낙관적 상태를 업데이트하는 함수 addOptimisticLike였다.

조쉬는 데모를 실행하며 동작을 단계별로 설명했다.

“초기 ‘좋아요’ 개수가 10이라고 가정합시다. 현재 likesoptimisticLikes는 모두 10입니다.”

그는 마우스로 버튼을 클릭했다.

handleLike 함수가 실행됩니다. 가장 먼저 addOptimisticLike(1)이 호출되죠. 이 순간, useOptimistic 훅은 실제 상태인 likes는 건드리지 않고, 오직 optimisticLikes의 값만 11로 바꾼 뒤 즉시 리렌더링을 일으킵니다.”

화면의 숫자가 10에서 11로 즉시 바뀌었다. 하트 아이콘도 채워진 모양으로 변했다. 사용자는 자신의 클릭이 즉각 반영되었다고 느낀다.

“그리고 바로 그 뒤에서, likePost(postId)라는 실제 서버 요청이 조용히 실행되기 시작합니다.”

그는 개발자 도구를 열어 네트워크 요청이 백그라운드에서 날아가는 것을 보여주었다.

“이제 가장 중요한 부분입니다. 만약 이 서버 요청이 실패하면 어떻게 될까요?”

조쉬는 강제로 서버 요청을 실패시켰다. 그러자 놀라운 일이 벌어졌다. 화면의 숫자 11이 스르륵, 다시 원래의 값인 10으로 되돌아왔다. 개발자가 롤백을 위한 코드를 단 한 줄도 작성하지 않았음에도 불구하고, React가 모든 것을 알아서 처리한 것이다.

useOptimistic 훅은 실제 상태인 likes의 값이 변경되지 않는 한, 서버 액션이 끝나는 시점에 낙관적 상태(optimisticLikes)를 자동으로 원래의 likes 값으로 되돌립니다. 이것이 바로 내장된 롤백 메커니즘입니다.”

이것이 바로 useOptimistic이 제공하는 마법이었다.

개발자는 더 이상 임시 상태, 로딩 상태, 에러 상태를 수동으로 조합할 필요가 없었다. 그저 ‘성공할 것이다’라는 가정 하에 UI를 먼저 업데이트하는 함수를 호출하기만 하면 됐다. 성공 시의 최종 상태 반영과 실패 시의 자동 롤백이라는 복잡한 과정은 모두 useOptimistic 훅 뒤에 완벽하게 추상화되어 있었다.

이 작은 훅 하나가, 개발자들이 수년간 마주해온 비동기 UI 처리의 복잡성을 순식간에 증발시켜 버렸다. ‘좋아요’ 버튼을 만드는 경험은 이제 더 이상 고통이 아닌, 즐거운 마법에 가까워질 터였다.