낙관적 업데이트
서버 응답을 기다리지 않고 UI를 먼저 업데이트한 뒤, 실패 시 롤백하는 클라이언트 측 기법입니다.
동작 흐름
- 사용자 액션 발생 (예: 좋아요 클릭)
- 서버 응답 전에 UI를 즉시 변경 (좋아요 +1 표시)
- 서버에 요청 전송
- 성공 → 그대로 유지 / 실패 → 이전 상태로 롤백
왜 사용하는가?
- 체감 속도 향상: 네트워크 지연(수백ms)을 사용자가 느끼지 않음
- UX 개선: 즉각적인 피드백으로 앱이 빠르게 느껴짐
- 대부분의 요청이 성공한다는 낙관적 가정에 기반
낙관적 vs 비관적 업데이트
| 항목 | 낙관적 (Optimistic) | 비관적 (Pessimistic) |
|---|---|---|
| UI 반영 시점 | 요청 즉시 | 서버 응답 후 |
| 체감 속도 | 빠름 | 느림 |
| 실패 처리 | 롤백 필요 | 별도 롤백 불필요 |
| 적합한 경우 | 성공률 높은 단순 작업 | 결제 등 실패 가능성 높은 작업 |
대표 사용 사례
- SNS 좋아요/북마크
- 메시지 전송 (카카오톡, Slack)
- 할 일 목록 체크/삭제
간단 예시 (React + React Query)
const likeMutation = useMutation(addLike, {
onMutate: async (postId) => {
// 1. 이전 상태 백업
const previous = queryClient.getQueryData(['post', postId]);
// 2. UI 즉시 업데이트
queryClient.setQueryData(['post', postId], old => ({
...old, likes: old.likes + 1
}));
return { previous };
},
onError: (err, postId, context) => {
// 3. 실패 시 롤백
queryClient.setQueryData(['post', postId], context.previous);
},
});
주의사항
- 롤백 로직을 반드시 구현해야 함 (빠뜨리면 데이터 불일치)
- 동시 요청이 많은 경우 경쟁 상태(race condition) 고려 필요
- 금융/결제처럼 실패 비용이 큰 작업에는 부적합