728x90
728x90

낙관적 업데이트(Optimistic Updates) (React Query)

들어가며

  • 리액트 쿼리(React Query)에서 사용되는 낙관적 업데이트(Optimistic Updates)에 대하여 정리해본다.

 

낙관적 업데이트(Optimistic Updating)

개념

  • 데이터가 실제 서버에 반영되기 전미리 UI에 반영하여 사용자 경험(UX)을 향상시키는 기법
  • 사용자가 서버 응답을 기다리지 않고도 즉각적인 피드백을 받을 수 있게 해준다.

 

주요 단계

① 변경 전 상태 저장

  • 낙관적 업데이트를 수행하기 전에, 현재 상태를 저장한다.
  • 이 작업은 서버 요청이 실패했을 경우 원래 상태로 롤백(Rollback)하기 위해 필요하다.

 

② 낙관적 상태 업데이트

  • 서버에 데이터를 전송하기 전에, 리액트 쿼리의 queryClient.setQueryData 메서드를 사용하여 로컬 상태를 즉시 업데이트한다.
    • 이 작업 전에 queryClient.cancelQueries 메서드를 사용하여 해당 쿼리에 대한 모든 활성 쿼리를 취소해줄 수 있다.
  • 이 작업은 사용자가 변경 사항을 즉시 확인할 수 있도록 한다.

 

③ 서버 요청 수행

  • 서버에 실제 데이터를 전송한다.
  • 이때 mutate 또는 mutateAsync 메서드를 사용한다.

 

④ 성공(또는 실패) 시 상태 반영

  • 서버 요청이 성공하면, 서버로부터 받은 최신 데이터를 다시 상태에 반영한다.
  • 이 작업은 onSettled 콜백 함수에서 수행된다.
    • 성공 시에만 상태를 반영하려면 onSuccess 콜백 함수를 사용한다.

 

⑤ 실패 시 롤백하기

  • 서버 요청이 실패하면, 저장해둔 원래 상태로 롤백한다.
  • 이 작업은 onError 콜백 함수에서 수행된다.

 

사용 예제

① 변경 전 상태 저장
  • handleSubmit 이벤트 핸들러 함수에서 mutate 메서드에 인자로 넘겨준 객체의 event prop의 값을 useMutation 훅의 onMutate 콜백 함수에서 data 값에 접근하여 가져올 수 있다.
import { useMutation } from '@tanstack/react-query';
const { mutate } = useMutation({
mutationFn: updateEvent,
onMutate: async (data) => {
// mutate() 함수에 인자로 전달한 것을 받아서 가져올 수 있다.
const newEvent = data.event;
}
}
function handleSubmit(formData) {
mutate({
id: params.id,
event: formData,
});
navigate('../');
}

 

② 낙관적 상태 업데이트
  • queryClient.cancelQueries 메서드를 이용하여 해당 쿼리에 대한 활성 쿼리를 취소해준다.
  • 그리고 queryClient.setQueryData 메서드를 사용하여 로컬 상태를 즉시 업데이트 해준다.
  • 그리고 에러 발생 시, 롤백을 하기 위해 이전의 값(previousEvent)을 return 해준다.
import { useMutation } from '@tanstack/react-query';
const { mutate } = useMutation({
mutationFn: updateEvent,
onMutate: async (data) => {
// mutate() 함수에 인자로 전달한 것을 받아서 가져올 수 있다.
const newEvent = data.event;
// 활성 쿼리 취소하기
await queryClient.cancelQueries({ queryKey: ['events', params.id] });
// 이전의 이벤트 정보 가져오기 (에러 발생 시 롤백하기 위해)
const previousEvent = queryClient.getQueryData(['events', params.id]);
// context로 반환
return { previousEvent };
}
}
function handleSubmit(formData) {
mutate({
id: params.id,
event: formData,
});
navigate('../');
}

 

 

③ 서버 요청 수행
  • mutate 함수를 사용하여 서버에 실제 데이터를 전송한다.
function handleSubmit(formData) {
mutate({
id: params.id,
event: formData,
});
navigate('../');
}

 

④ 성공(또는 실패) 시 상태 반영
  • onSettled 콜백 함수에 서버 요청 성공/실패와 상관 없이 수행할 작업들을 넣는다.
    • 서버 요청이 성공할 시에만 처리하려면 onSuccess 콜백 함수에 해당 작업을 넣는다. 
  • queryClient.invalidateQueries를 사용하여 최신 데이터를 백엔드에서 가져온다.
import { useMutation } from '@tanstack/react-query';
const { mutate } = useMutation({
mutationFn: updateEvent,
onMutate: async (data) => {
// mutate() 함수에 인자로 전달한 것을 받아서 가져올 수 있다.
const newEvent = data.event;
// 활성 쿼리 취소하기
await queryClient.cancelQueries({ queryKey: ['events', params.id] });
// 이전의 이벤트 정보 가져오기 (에러 발생 시 롤백하기 위해)
const previousEvent = queryClient.getQueryData(['events', params.id]);
// context로 반환
return { previousEvent };
}
onSettled: () => {
// 성공하든 실패하든 처리할 작업
queryClient.invalidateQueries(['events', params.id]);
},
});
}
function handleSubmit(formData) {
mutate({
id: params.id,
event: formData,
});
navigate('../');
}

 

⑤ 실패 시 롤백하기
  • 서버 요청이 실패하면 저장해둔 원래 상태로 롤백한다.
  • onError 콜백 함수에 해당 코드를 넣는다.
  • 이때 onError 콜백 함수의 context 매개변수에 접근하여 onMutate 콜백 함수에서 return 했던 previousEvent 값을 가져올 수 있다.
import { useMutation } from '@tanstack/react-query';
const { mutate } = useMutation({
mutationFn: updateEvent,
onMutate: async (data) => {
// mutate() 함수에 인자로 전달한 것을 받아서 가져올 수 있다.
const newEvent = data.event;
// 활성 쿼리 취소하기
await queryClient.cancelQueries({ queryKey: ['events', params.id] });
// 이전의 이벤트 정보 가져오기 (에러 발생 시 롤백하기 위해)
const previousEvent = queryClient.getQueryData(['events', params.id]);
// context로 반환
return { previousEvent };
}
onError: (error, data, context) => {
queryClient.setQueryData(['events', params.id], context.previousEvent);
},
onSettled: () => {
// 성공하든 실패하든 처리할 작업
queryClient.invalidateQueries(['events', params.id]);
},
});
}
function handleSubmit(formData) {
mutate({
id: params.id,
event: formData,
});
navigate('../');
}

 

 

  • 실행 화면은 다음과 같다.

 

참고 사이트

 

Optimistic Updates | TanStack Query React Docs

React Query provides two ways to optimistically update your UI before a mutation has completed. You can either use the onMutate option to update your cache directly, or leverage the returned variables to update your UI from the useMutation result. Via the

tanstack.com

 

728x90
728x90

낙관적 업데이트(Optimistic Updates) (React Query)들어가며낙관적 업데이트(Optimistic Updating)개념주요 단계① 변경 전 상태 저장② 낙관적 상태 업데이트③ 서버 요청 수행④ 성공(또는 실패) 시 상태 반영⑤ 실패 시 롤백하기사용 예제참고 사이트