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('../');
}
- 실행 화면은 다음과 같다.
참고 사이트
728x90
728x90
'Programming > React' 카테고리의 다른 글
[React.js] 조건부 렌더링 방법 정리 (0) | 2024.08.22 |
---|---|
[React.js] Compound Component 패턴 (0) | 2024.08.12 |
[React.js] Framer Motion 라이브러리 (0) | 2024.08.11 |
[React.js] Suspense 컴포넌트 (0) | 2024.08.06 |
[React.js] 리액트 쿼리(Tanstack Query, React Query) (0) | 2024.07.09 |
[React.js] 지연 로딩(Lazy Loading) (0) | 2024.07.08 |
[React.js] useSearchParams 훅 (React Router) (0) | 2024.07.08 |
[React.js] defer() (React Router) (0) | 2024.07.07 |