optimistic update란 번역대로 낙관적인 업데이트이다.
사용자 입장에서 어떤 인터랙션을 통해서 변화가 일어날 것이라는 예측이 된다면 이 방법을 사용해보는 것도 괜찮을 것 같다.
예로 사용자가 인스타그램의 게시물에 하트를 누르면 하트가 빨간하트가 되고 다시 누르면 하트가 빈 하트가 될 것이라는 예측이 된다.
이를 통해 현재 진행하고 있던 쇼핑몰 프로젝트에서 상품에 대한 하트 누르기 및 하트 취소하기 기능을 적용하면서
react query에서 제공하는 optimistic update를 사용하기로 하였다.
하트를 누를 시의 optimistic update 코드
const {mutate: addLike} = useMutation((data: number) => apis.Product.addLike(data),
{
onMutate: async(variable) => {
await queryClient.cancelQueries({queryKey: ['getProducts']})
const previous = queryClient.getQueryData(['getProducts']);
queryClient.setQueryData<InfiniteData<Array<any>>>(['getProducts'], (old:any) => {
const newData = old?.pages.map((page:any) =>
page.map((value:any) => {
if(value.id === variable){
return {
...value,
Likers: [...value.Likers, {id: me?.id}]
}
}else{
return value
}
})
)
return {
...old,
pages:newData
}
})
return { previous }
},
onError: (err: any, param, context) => {
if(err.response.status = 401){
router.push('/signin')
}else{
queryClient.setQueryData(['getProducts'], context?.previous)
}
},
onSettled: () => {
queryClient.invalidateQueries({queryKey: ['getProducts']})
}
});
onMutate
onMutate란 addLike라는 mutate가 실행되기 전에 실행되는 함수이다.
addLike라는 mutate가 실행되기 전에 cancelQueries['getProducts']로 상품들의 목록을 가져오는 usequery를 막는다.
이를 수행하는 이유는 optimistic update를 통해 데이터를 수정할때 데이터가 overwrite되는 현상을 막기 위해서 이다.
const previous = queryClient.getQueryData(['getProducts'])를 통해 수정하기 이전 값을 스냅샷 한다.
setQueryData를 통해서 상품목록을 가져오는 query 데이터를 수정해야한다.
즉 프론트 단에서 낙관적 업데이트가 적용된 데이터로 탈바꿈하는 것이다.
상단 코드 같은 경우에는 infinite queries를 사용하기 때문에 조금 다르다.
old라는 파라미터는 객체 형태이고 pageParams와 pages의 형태로 구성되어 있다.
실제적인 데이터는 pages 배열의 각 value 값에 해당된다.

이 previous라는 데이터를 기준으로 Likers 배열에 나의 id를 넣는 로직을 작성하여
pages 배열 값을 수정한 값을 업데이트 시켜준다.
끝으로 return {previous} 를 통해 이전 값을 리턴해준다.
onError
이 값은 onError시에 사용 될 수 있다. context.previous를 통해서 가져와서 사용할 수 있으며
만약 에러가 발생한다면 다시 이전 값으로 롤백 시키기 위함이라고 생각하면 된다.
onSettled
onSettled는 성공 유무에 상관없이 실행할 로직을 의미한다.
낙관적 업데이트가 성공했든 실패했든 서버의 최신 상태를 반영해야하므로 invalidateQueries를 통해
마지막으로 목록을 최신화 시킨다.
optimistic update란 번역대로 낙관적인 업데이트이다.
사용자 입장에서 어떤 인터랙션을 통해서 변화가 일어날 것이라는 예측이 된다면 이 방법을 사용해보는 것도 괜찮을 것 같다.
예로 사용자가 인스타그램의 게시물에 하트를 누르면 하트가 빨간하트가 되고 다시 누르면 하트가 빈 하트가 될 것이라는 예측이 된다.
이를 통해 현재 진행하고 있던 쇼핑몰 프로젝트에서 상품에 대한 하트 누르기 및 하트 취소하기 기능을 적용하면서
react query에서 제공하는 optimistic update를 사용하기로 하였다.
하트를 누를 시의 optimistic update 코드
const {mutate: addLike} = useMutation((data: number) => apis.Product.addLike(data),
{
onMutate: async(variable) => {
await queryClient.cancelQueries({queryKey: ['getProducts']})
const previous = queryClient.getQueryData(['getProducts']);
queryClient.setQueryData<InfiniteData<Array<any>>>(['getProducts'], (old:any) => {
const newData = old?.pages.map((page:any) =>
page.map((value:any) => {
if(value.id === variable){
return {
...value,
Likers: [...value.Likers, {id: me?.id}]
}
}else{
return value
}
})
)
return {
...old,
pages:newData
}
})
return { previous }
},
onError: (err: any, param, context) => {
if(err.response.status = 401){
router.push('/signin')
}else{
queryClient.setQueryData(['getProducts'], context?.previous)
}
},
onSettled: () => {
queryClient.invalidateQueries({queryKey: ['getProducts']})
}
});
onMutate
onMutate란 addLike라는 mutate가 실행되기 전에 실행되는 함수이다.
addLike라는 mutate가 실행되기 전에 cancelQueries['getProducts']로 상품들의 목록을 가져오는 usequery를 막는다.
이를 수행하는 이유는 optimistic update를 통해 데이터를 수정할때 데이터가 overwrite되는 현상을 막기 위해서 이다.
const previous = queryClient.getQueryData(['getProducts'])를 통해 수정하기 이전 값을 스냅샷 한다.
setQueryData를 통해서 상품목록을 가져오는 query 데이터를 수정해야한다.
즉 프론트 단에서 낙관적 업데이트가 적용된 데이터로 탈바꿈하는 것이다.
상단 코드 같은 경우에는 infinite queries를 사용하기 때문에 조금 다르다.
old라는 파라미터는 객체 형태이고 pageParams와 pages의 형태로 구성되어 있다.
실제적인 데이터는 pages 배열의 각 value 값에 해당된다.

이 previous라는 데이터를 기준으로 Likers 배열에 나의 id를 넣는 로직을 작성하여
pages 배열 값을 수정한 값을 업데이트 시켜준다.
끝으로 return {previous} 를 통해 이전 값을 리턴해준다.
onError
이 값은 onError시에 사용 될 수 있다. context.previous를 통해서 가져와서 사용할 수 있으며
만약 에러가 발생한다면 다시 이전 값으로 롤백 시키기 위함이라고 생각하면 된다.
onSettled
onSettled는 성공 유무에 상관없이 실행할 로직을 의미한다.
낙관적 업데이트가 성공했든 실패했든 서버의 최신 상태를 반영해야하므로 invalidateQueries를 통해
마지막으로 목록을 최신화 시킨다.