TanStack Query로 낙관적 업데이트 적용하기
낙관적 업데이트를 적용을 통해 사용자 경험을 개선해보자
2024.11.15
15분 소요
글을 시작하며
펭귄이라는 매게체를 통해 가족 간 일상과 추억을 공유할 수 있는 서비스 가까이를 개발하며 낙관적 업데이트의 필요성에 대해 느끼고 도입했던 경험에 대해 작성해보고자 합니다.
만약 사용자가 펭귄의 상태를 변경하려고 할 때, 요청을 보내고 응답이 오기까지 2초의 시간이 걸린다면 사용자는 2초 동안 기다렸다가, 2초 뒤에야 변경된 펭귄을 확인할 수 있습니다.
사용자는 바로 바로 바뀌는 펭귄을 기대하지만 실제로는 2초의 시간이 걸리기 때문에 사용자 경험이 떨어지게 됩니다. 사용자들은 누른 순간 즉시 변경되는 귀여운 펭귄을 기대하지 않을까요?
실제로 2초라는 시간이 걸렸던 것은 아니지만, 약간의 딜레이가 발생했고 이를 해결해보고자 낙관적 업데이트를 적용해보기로 했습니다.
낙관적 업데이트란?
낙관적 업데이트는 사용자의 액션이 성공할 것이라고 가정하고, 네트워크 응답을 기다리기 전에 UI를 먼저 업데이트하는 기법입니다. 이를 통해 사용자는 서버 응답을 기다리지 않고 즉시 피드백을 받을 수 있어, 실시간으로 변화를 체감하게 됩니다.
예를 들어, 사용자가 펭귄의 상태를 변경하는 요청을 보냈을 때, 서버 응답을 기다리지 않고 바로 변경된 UI를 보여줄 수 있습니다. 그 결과, 사용자에게는 즉각적인 반응을 제공하며, 대기 시간을 최소화할 수 있습니다.
TanStack Query로 낙관적 업데이트 적용하기
TanStack Query에서는 onMutate, onError, onSettled 같은 콜백 함수들을 활용하여 낙관적 업데이트를 손쉽게 구현할 수 있습니다.
- onMutate: 서버 요청 전에 기존 데이터를 백업하고, UI에 낙관적 업데이트 적용
- onError: 요청이 실패하면 이전 데이터로 롤백
- onSettled: 요청이 완료된 후 서버 데이터를 다시 불러와 최신 상태로 갱신
useMutation({
mutationFn: (decoration: decoType) => patchPenguinDecoration(decoration),
onMutate: async (decoration: decoType) => {
// 쿼리키에 대한 모든 퀴리요청을 취소하여 낙관적 업데이트가 서버 응답으로 덮어 씌어지지 않도록 방지
await queryClient.cancelQueries({ queryKey: ['userInfo'] });
// 기존 데이터 snapshot을 가져옴
const previousUserInfo = queryClient.getQueriesData({ queryKey: ['userInfo'] });
// 새로운 데이터로 낙관적 업데이트 실시
queryClient.setQueryData(['userInfo'], (old: APIResponse<IUserInfoReq>) => {
return {
...old,
data: {
...old.data,
decoration,
},
};
});
// 이후에 에러 발생 시 이전 데이터로 롤백하기 위해 context를 return
return { previousUserInfo };
},
onError: (error, _, context) => {
// 에러 발생 시 이전데이터로 롤백
queryClient.setQueryData(['userInfo'], context?.previousUserInfo);
console.log(error);
},
onSettled: () => {
// 결과에 상관없이 실행되며 데이터를 최신 상태로 갱신
queryClient.invalidateQueries({ queryKey: ['userInfo'] });
},
});
결론
낙관적 업데이트는 빠른 사용자 피드백을 제공하여 사용자 경험을 개선할 수 있는 좋은 전략 중 하나라고 생각합니다.
TanStack Query를 사용하면 낙관적 업데이트를 간단하게 구현할 수 있으며, 네트워크 요청 대기 시간을 줄이고, 더 나은 사용자 경험을 제공할 수 있습니다.
그러나, 이 기법은 예측에 기반한 것이기 때문에(사용자의 액션이 성공할 것이라고 가정), 서버 응답 실패 시 롤백 로직을 함께 구현하여 잠재적 실패에 대응할 필요가 있습니다.
상황에 맞게 낙관적 업데이트를 적용하여 사용자 경험을 개선해보세요!