
컴퓨터가 느린 환경에 있거나 백엔드 서버가 물리적으로 멀리 있다면 mutation 요청을 하고 응답을 받는데까지 시간이 오래 걸릴 수 있다. 가령 좋아요 버튼을 누르는 간단한 요청을 보냈는데 응답이 2-3초 걸린다면 사용자 경험에 굉장히 좋지 않은 영향을 끼칠 것이다. 이럴 때 optimistic-ui를 사용하게 된다.
optimistic-ui는 요청을 보냄과 동시에 글로벌 스테이트를 변경하고 화면의 값을 바꾸는 것이다. 요청이 성공하면 응답으로 들어온 결과값으로 화면을 업데이트한다. 하지만 optimistic-ui로 이미 화면의 값은 바뀌어있기 때문에 사용자가 보기엔 똑같다.
요청이 실패하게 되면 이전의 값을 응답으로 보내주게 되고 그 값으로 화면을 업데이트 한다.
const FETCH_BOARD = gql`
query fetchBoard($boardId: ID!) {
fetchBoard(boardId: $boardId) {
_id
likeCount
}
}
`;
const LIKE_BOARD = gql`
mutation likeBoard($boardId: ID!) {
likeBoard(boardId: $boardId)
}
`;
export default function OptimisticUiPage(): JSX.Element {
const { data } = useQuery<Pick<IQuery, "fetchBoard">, IQueryFetchBoardArgs>(
FETCH_BOARD,
{
variables: { boardId: "board id" },
},
);
const [likeBoard] = useMutation<
Pick<IMutation, "likeBoard">,
IMutationLikeBoardArgs
>(LIKE_BOARD);
const onClickLike = (): void => {
void likeBoard({
variables: {
boardId: "board id",
},
// refetchQueries: [{}],
optimisticResponse: {
likeBoard: (data?.fetchBoard.likeCount ?? 0) + 1,
},
update: (cache, { data }) => {
cache.writeQuery({
query: FETCH_BOARD,
variables: { boardId: "board id" },
data: {
fetchBoard: {
_id: "board id",
__typename: "Board",
likeCount: data?.likeBoard, // optimisticResponse에서 받아온 Data
},
},
});
},
});
};
return (
<>
<div>현재 카운트(좋아요) : {data?.fetchBoard?.likeCount}</div>
<button onClick={onClickLike}>좋아요 올리기!</button>
</>
);
}
optimisticResponse 옵션을 사용해 작성한다.
optimistic-ui는 실패 확률이 낮고 중요도가 낮은 요청에만 사용하도록 한다. 사용자에게 만족도 높은 경험을 줄 수 있기에 중요하지 않은 요청이라면 optimistic-ui를 사용하는 것이 좋다.