[React] 좋아요 낙관적 업데이트 적용하기

2025. 7. 21. 14:18·웹/React

낙관적 업데이트

낙관적 업데이트란 서버로부터 응답을 받기 전 UI를 미리 업데이트 하는 방법이다.

사용자에게 빠른 피드백을 줄 수 있기 때문에 자주 사용된다.

그러나 서버로부터의 응답이 실패했을 경우 롤백하는 적절한 처리가 필요하며, 무분별하게 사용하면 사용자로부터 신뢰를 잃을 수 있으므로 빠른 상호작용이 중요하지만 중요하지 않은 데이터에 적용할 수 있겠다.

 

나의 경우, <코코> 프로젝트에서 낙관적 업데이트를 적용했고, 서버로부터 에러가 발생했을 때 롤백하는 로직까지 구현해보았다.

좋아요 기능 같은 경우는 즉각적으로 반영되는 것이 사용자의 입장에서 필수적인 경험이라고 생각했기 때문이다.

 

낙관적 업데이트 시나리오

  • 흐름: 좋아요 관련 local state 변경 → UI 렌더링 → 좋아요 api 호출
  • 롤백: local state 변경 → 서버 에러 → local state 원상복귀

 

구현

(1) 로컬 state

const [localLike, setLocalLike] = useState(liked);
const [localLikeCount, setLocalLikeCount] = useState(likeCount);

로컬 state를 선언해준다. 이때 초기값으로 설정 되어 있는 liked 와 likeCount 는 서버로부터 얻은 데이터이다. (props로 내려준 형태)

초기 서버 값과 로컬 상태가 동기화되어 있는 상태다.

 

(2) 좋아요 기능 함수 - 낙관적 업데이트 로직

  
  const handleLike = async () => {

    // 좋아요 취소
    if (localLike && localLikeCount > 0) {
    
	    // 낙관적 업데이트
      setLocalLike(prev => !prev);
      setLocalLikeCount(prev => prev - 1);
      
      try {
        await deleteLikeMutation.mutateAsync(postId);
      } catch {
	      // 롤백
        setLocalLike(prev => !prev);
        setLocalLikeCount(prev => prev + 1);
      }
      
    }
    // 좋아요 등록
    else if (!localLike) {
   
       // 낙관적 업데이트
      setLocalLike(prev => !prev);
      setLocalLikeCount(prev => prev + 1);
      
      try {
        await registerLikeMutation.mutateAsync(postId);
      } catch {
	      // 롤백
        setLocalLike(prev => !prev);
        setLocalLikeCount(prev => prev - 1);
      }
    }
    
  };

localLike 와 localLikeCount 상태를 먼저 변경한 후 api를 호출하도록 구현하였다.

요청이 실패할 경우 해당 state를 다시 원상복귀 하는 롤백 로직은 catch문을 통해서 수행된다.

(Promise가 reject될 경우 catch문 수행되므로)

 

(3) UI

   {/* 좋아요 버튼 */}
      <button
        onClick={handleLike}
        disabled={isAnimating}
      >
        {/* 하트 아이콘 */}
        <div className="relative">
          <svg
           width="20"
            height="20"
            viewBox="0 0 24 24"
            className={`
                  transition-all duration-300 ease-out
                  ${localLike ? 'fill-current scale-110' : 'fill-none'}
                  ${isAnimating ? 'animate-pulse' : ''}
                `}
            stroke="currentColor"
            strokeWidth="2"
          >
            <path d="M20.84 4.61a5.5 5.5 0 0 0-7.78 0L12 5.67l-1.06-1.06a5.5 5.5 0 0 0-7.78 7.78l1.06 1.06L12 21.23l7.78-7.78 1.06-1.06a5.5 5.5 0 0 0 0-7.78z" />
          </svg>
        </div>

        {/* 좋아요 카운트 */}
        <span
          className={`
              font-medium transition-all duration-300 ease-out
              ${isAnimating ? 'scale-105' : ''}
              ${localLike ? 'text-red-600' : ''}
            `}
        >
          {localLikeCount}
        </span>
      </button>

좋아요 버튼 내에서 localLike , localLikeCount에 따라 좋아요 여부를 표시하여 빠른 반영이 가능하다.

 

 

'웹 > React' 카테고리의 다른 글

[React 딥다이브🌊] fiber 아키텍처와 동기 렌더링-커밋 프로세스 코드 뜯어보기  (4) 2025.08.03
[React] memo, useCallback을 사용한 렌더링 최적화  (3) 2025.07.08
[코드 개선하기] try, catch vs React Query의 onSuccess, onError : 비동기 처리 로직 통일하기  (0) 2025.06.25
[React] 폰트 최적화 + preload 적용해 사용자 경험 개선하기  (0) 2025.06.23
[React, Vite, Vite-bundle-analyzer] CSR에서 초기 로딩 시간 단축하기 2 - 라이브러리 청크 단위로 정적 분리  (0) 2025.06.03
'웹/React' 카테고리의 다른 글
  • [React 딥다이브🌊] fiber 아키텍처와 동기 렌더링-커밋 프로세스 코드 뜯어보기
  • [React] memo, useCallback을 사용한 렌더링 최적화
  • [코드 개선하기] try, catch vs React Query의 onSuccess, onError : 비동기 처리 로직 통일하기
  • [React] 폰트 최적화 + preload 적용해 사용자 경험 개선하기
Hyemimi
Hyemimi
배움의 과정에서 느껴지는 소소한 즐거움을 중요시합니다 🌱
  • Hyemimi
    Hyemi.techlog
    Hyemimi
  • 전체
    오늘
    어제
    • 분류 전체보기 (32)
      • 웹 (15)
        • React (10)
        • Next (1)
      • 앱 (0)
        • Flutter (0)
      • 회고 (2)
        • 카카오테크 부트캠프 (4)
      • 언어 (1)
        • JavaScript (0)
        • TypeScript (1)
        • Python (0)
      • CS (3)
      • 알고리즘 (5)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    CSR
    비동기
    판교부트캠프
    OSSCA
    부트캠프추천
    카테부
    kakaotechbootcamp
    오픈소스 컨트리뷰션 아카데미
    폰트 최적화
    react
    부트캠프
    최적화
    KTB
    카테부커뮤니티
    카카오
    preload
    Kakao
    Vite
    카카오테크부트캠프
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.2
Hyemimi
[React] 좋아요 낙관적 업데이트 적용하기
상단으로

티스토리툴바