좋아요를 눌러도 서버 응답까지 화면이 멈춰 있던 것을 고친 방법
문제 발생
좋아요 버튼이 서버 왕복을 기다리는 동안 아무 반응이 없었습니다.
async function like() {
await likePost(id); // 300~800ms
}직접 낙관적 상태를 만들려니 실패했을 때 되돌리는 코드, 연속 클릭 처리, 서버 값과의 동기화가 전부 손으로 짜야 하는 일이 됐습니다.
원인 분석
React에 이 패턴을 위한 훅이 있습니다. 문서 설명대로 useOptimistic은 비동기 Action이 진행되는 동안 임시 상태 값을 표시해 사용자에게 즉시 피드백을 줍니다.
되돌리기도 자동입니다 — setter가 Action 안에서 호출되면 React가 리렌더해 그 상태를 보여주고, 그 밖의 경우에는 useOptimistic에 전달한 value를 반환합니다. 그리고 Action이 실패해 오류를 던지면 React는 현재 value로 렌더하는데, 부모는 보통 성공했을 때만 value를 갱신하므로 실패는 곧 낙관적 업데이트 이전 화면으로 돌아가는 것을 뜻합니다.
한 가지 제약이 있습니다 — setter는 반드시 Action이나 Transition 안에서 호출해야 하며, 밖에서 호출하면 경고와 함께 낙관적 상태가 잠깐 렌더됐다가 되돌아갑니다.
해결 방안
- 서버 값과 낙관적 값을 함께 선언합니다.
const [optimisticLikes, addOptimisticLike] = useOptimistic(
likes,
(current, delta) => current + delta,
);- 액션 안에서 갱신합니다.
<form action={async () => {
addOptimisticLike(1);
await likePost(id);
}}>-
실패 처리를 서버 값에 맡깁니다. 별도 롤백 코드를 쓰지 않습니다 — 액션이 실패하면 부모의
likes가 그대로이므로 화면이 알아서 되돌아갑니다. -
낙관적 표시를 남용하지 않습니다. 결제나 삭제처럼 되돌릴 수 없거나 실패가 흔한 동작은 낙관적으로 보여주면 사용자를 속이게 됩니다. 좋아요·북마크처럼 실패해도 손실이 적은 곳에 씁니다.
-
연속 클릭을 감안합니다. reducer 형태로 델타를 누적하면 여러 번 눌러도 값이 자연스럽게 쌓입니다.
-
서버가 진실입니다. 낙관적 값은 화면용이므로, 목록 갱신이나 재검증으로 실제 값이 들어오면 그쪽이 이깁니다.
댓글0
댓글을 남기려면 로그인이 필요해요. 로그인
아직 댓글이 없어요. 첫 의견을 편하게 남겨 보세요.