yooveloper5673
얼마 전, 낙관적 업데이트라는 사용자 경험 개선 방법에 대해 알게 되었어요. 요점은 아래와 같아요.
낙관적 업데이트의 장점은 네트워크 지연이나 서버의 응답을 기다리지 않고 미리 상태를 업데이트함으로써 사용자에게 즉각적인 UI를 제공한다는 데 있는 것 같아요.
아마 대부분 React Query를 사용하면서 많이들 적용하는 것 같은데, 처음 들었을 때는 이런 생각이 들었어요.
“어? 클라이언트에서 마음대로 서버 상태를 변경해도 될까?” (물론 실제 서버에 commit되진 않고 클라이언트 캐시를 변경하는 것이지만요.)
만약 서버 응답이 실패하면, 사용자는 변경된 UI를 봤다가 다시 롤백되는 경험을 하게 될 텐데, 이걸 버그라고 생각하지 않을까 걱정되기도 했어요.
import { useMutation, useQueryClient } from '@tanstack/react-query';
function useLikePost(postId: number) {
const queryClient = useQueryClient();
return useMutation({
mutationFn: async () => {
// 서버에 좋아요 요청 보내기
await fetch(`/api/posts/${postId}/like`, { method: 'POST' });
},
onMutate: async () => {
// 1. 서버 요청 전에 쿼리 취소
await queryClient.cancelQueries({ queryKey: queryKeys.post(postId) });
// 2. 이전 데이터 저장
const previousPost = queryClient.getQueryData<{ likes: number }>(queryKeys.post(postId));
// 3. 낙관적 업데이트 적용
queryClient.setQueryData(queryKeys.post(postId), (old) => {
if (!old) return old;
return { ...old, likes: old.likes + 1 };
});
// 4. rollback을 위한 이전 데이터 반환
return { previousPost };
},
onError: (_err, _variables, context) => {
// 5. 실패 시 rollback
if (context?.previousPost) {
queryClient.setQueryData(queryKeys.post(postId), context.previousPost);
}
},
onSettled: () => {
// 6. 성공/실패와 관계없이 최종적으로 서버에서 데이터 재요청
queryClient.invalidateQueries({ queryKey: queryKeys.post(postId) });
},
});
}
여러분은 낙관적 업데이트에 대해 어떻게 생각하시나요? 좋은 UX 패턴이라고 생각하시나요? 실제로 운영 중인 서비스에서 적용해본 경험이 있다면 소개해주시면 너무 감사할 것 같아요. 또, 어떤 케이스에 적용하면 좋을지도 같이 얘기해 보면 좋겠네요.