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
'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 |