reactuseoptimisticux
useOptimistic으로 낙관적 업데이트 제대로 쓰기
✨ AI 요약
긴 글, 핵심만 먼저 — 이 글을 3줄로 정리해드려요.
조회 29
좋아요 버튼을 눌렀는데 0.5초 뒤에 하트가 채워진다면, 그 0.5초는 사용자에게 "고장났나?"의 시간이다. 낙관적 업데이트는 서버 응답을 기다리지 않고 UI를 먼저 바꾸는 기법이고, React 19의 useOptimistic은 이걸 공식 패턴으로 만들었다.
수동 구현의 함정
useState로 직접 하면 이렇게 된다.
setLiked(true); // 낙관적 반영
const res = await toggleLike(id);
if (!res.ok) setLiked(false); // 롤백
문제는 연타다. 두 번 빠르게 누르면 요청 두 개가 경쟁하고, 늦게 도착한 응답이 최신 상태를 덮어쓴다. 롤백 로직이 상태 꼬임의 진원지가 된다.
useOptimistic의 핵심
const [optimisticLikes, addOptimistic] = useOptimistic(
likes, // 서버가 준 진짜 값
(current, delta: number) => current + delta,
);
function onLike() {
startTransition(async () => {
addOptimistic(1);
await toggleLike(id); // 끝나면 서버 값으로 자동 복귀
});
}
포인트는 롤백 코드가 없다는 것. 낙관적 상태는 트랜지션이 진행되는 동안만 존재하는 오버레이고, 액션이 끝나면 서버에서 리밸리데이트된 진짜 값이 그 자리를 차지한다. 실패해도 진짜 값으로 돌아갈 뿐이다.
실무 체크리스트
- 낙관적 반영이 어울리는 곳: 좋아요, 북마크, 팔로우 — 실패해도 피해가 없는 토글
- 어울리지 않는 곳: 결제, 발행, 삭제 — 실패가 심각하면 기다리는 게 맞다
- 서버 액션과 함께 쓸 때는 revalidatePath까지 해야 "진짜 값"이 갱신된다
- 연타 대응은 서버에서도: 토글 API는 멱등적으로 설계하자
낙관적 업데이트는 UX 기법이기 전에 상태 소유권 문제다. "진짜 상태는 서버 것, 화면은 잠깐 앞서갈 뿐" — 이 원칙만 지키면 꼬일 일이 없다.