낙관적 Optimistic
optimistic-ui 란 단어 그대로 낙관적인! UI 임.
요청 결과가 오류가 나지 않을 것을 미리 예상하고 사용자애개 성공 시 결과를 바로 보여주는 것이다.
그것도 실제 요청 결과가 나오기 전에 말이다.
요청이 올 때까지 기다리는 대신 먼저 UI를 변경해두고, success response
가 오지 않을 경우에는 에러처리 or 롤백 처리를 하여서 UI를 수정한다.
주의사항: 혹시 모를 에러에 대한 로직을 작성해 두지 않는다면 사용자 입장에서는 분명 요청이 성공된 것으로 봤는데 실제로는 실패한 상황인 것을 보게 된다.
import { gql, useMutation, useQuery } from "@apollo/client";
const FETCH_BOARD = gql`
query fetchBoard($boardId: ID!) {
fetchBoard(boardId: $boardId) {
_id
likeCount
}
}
`;
// 좋아요 카운트 올리는 api
const LIKE_BOARD = gql`
mutation likeBoard($boardId: ID!) {
likeBoard(boardId: $boardId)
}
`;
export default function OptimisticUIPage() {
const [likeBoard] = useMutation(LIKE_BOARD);
const { data } = useQuery(FETCH_BOARD, {
variables: { boardId: "62b3c48d03610b0029990501" },
});
const onClickLike = () => {
likeBoard({
variables: {
boardId: "62b3c48d03610b0029990501",
},
// 응답을 받고난 후 받아온 응답을 다시 fetch 해줍니다.
// -> 느리고 효율적이지 못합니다.(백엔드에 요청을 한번더 해야하고 받아올때 까지 기다려야 합니다.)
// refetchQueries: [
// {
// query: FETCH_BOARD,
// variables: { boardId: "62b3c48d03610b0029990501" },
// },
// ],
// 옵티미스틱 UI -> 캐시를 바꾸고 캐시값을 받아오는걸 기다리지 않고 바로 바꿔줌
// 현재 좋아요 수 + 1 , 만약에 좋아요가 없다면 0으로.
optimisticResponse: {
likeBoard: (data?.fetchBoard.likeCount || 0) + 1,
},
// apollo 캐시를 직접 수정을 할 수 있었습니다.(백엔드 캐시가 아닙니다.) -> 느리지만 효율적
update(cache, { data }) {
cache.writeQuery({
query: FETCH_BOARD,
variables: {
boardId: "62b3c48d03610b0029990501",
},
// id,__typename 가 반드시 들어가야한다.
data: {
fetchBoard: {
likeCount: data.likeBoard,
_id: "62b3c48d03610b0029990501",
__typename: "Board",
},
},
});
},
});
};
return (
<>
<h1>옵티미스틱 UI</h1>
<div>현재 카운트(좋아요): {data?.fetchBoard.likeCount}</div>
<button onClick={onClickLike}>조항요!!</button>
</>
);
}
refetch를 통해 완료 요청이 왔을때 화면을 그려줬지만 optimisticResponse
를 이용해 apollo client
에 optimistic
버전으로 저장되면 apollo client
가 이를 보고 저장된 데이터를 가지고 연관되어 있는 컴포넌트들을 재랜더링한다.
이제 진짜 실제 완료요청 데이터를 받으면 apollo client
는 기존의 버전을 지우고 서버에서 받은 데이터를 저장하고 적용한다! (그후 재랜더링)