옵티미스틱 UI

SongNoin·2021년 10월 24일
0
post-thumbnail

옵티미스틱 UI

좋아요 버튼을 누른다 생각했을때 !

  • 기존의 UI는..

  1. 사용자가 좋아요버튼을 누른다.
  2. onClick 함수가 실행되고 서버에 mutation 요청을 보내게 된다.
  3. 서버에 보낸 요청이 완료될때까지 await로 기다린다.
  4. 완료됐다는 응답이 오면 이제 refetch해서 좋아요 갯수 데이터를 다시 가져온다.
  5. 가져온 데이터를 화면에 보여준다.

  • Optimistic UI

단어 그대로 낙관적으로 생각하는 UI이다. 서버로부터 받는 응답이 대부분 오류가 나지 않을 것이다. 성공적일 것이다라고 가정하고 사용자에게 성공했을때의 결과를 바로 보여주는 것이다.

  1. 사용자가 좋아요버튼을 누른다.
  2. 좋아요 갯수가 1개 증가한 UI를 바로 보여준다.
  3. 서버에 mutation을 요청한다.
  4. 서버에서 응답을 받습니다.

만약 오류가 발생했을 경우면?
성공할거라고 예상했는데 서버에서 뒤늦게 에러가 났다는 응답이 오면 어떻게 해야할까

  1. 사용자가 좋아요버튼을 누른다.
  2. 버튼 색상이 바뀌면서 좋아요가 눌렸음을 바로 알려준다.
  3. 서버에 요청한다.
  4. 서버에서 실패했다는 응답을 받습니다.
  5. 조용히 좋아요 버튼의 색깔을 변경합니다.

이렇게 하면 이용자가 에러창으로 방해 받지 않고 색상이 다시 변경되기도 하고,
색상이 다시 변경되었기 때문에 다시 시도해야겠다는 색가을 자연스럽게 하게 된다.

물론 Optimistic UI는 좋아요버튼이나 찜하기 버튼등 근본적인 서비스에 큰 영향이 없는 시스템에 적용해야한다. 에러메시지를 분명하게 알아야하는 서비스에는 절대 적용해서는 안된다.

이렇게 약간의 하얀 거짓말을 통해 이용자의 편의를 증대할 수 있다는 방법이 참 재밌는 것 같다.

💻 코드에 적용하기

import { gql, useMutation, useQuery } from "@apollo/client";
...
// query문 생략
...
export default function OptimisticUIPage() {
  const [likeBoard] = useMutation(LIKE_BOARD);
  const { data } = useQuery(FETCH_BOARD, {
    variables: { boardId: "6170da6cb55052002a93d0f3" },
  });
  const onClickLike = () => {
    likeBoard({
      variables: { boardId: "6170da6cb55052002a93d0f3" },
      //   refetchQueries: [
      //     {
      //       query: FETCH_BOARD,
      //       variables: { boardId: "6170e1c2b55052002a93d14b" },
      //     },
      //   ], // 이거는 리페치 될 때까지 기다려야됨
  • optimisticResponse를 사용해야 아폴로 클라이언트 캐시에 따로 저장해서 Optimistic UI를 이용할수 있다.

  • 99% 확률로 성공할수 있는것만 써야한다.

      optimisticResponse: {
        // 아폴로 클라이언트 캐시에 optimisticResponse버전으로 따로 저장된다.
        // 99% 확률로 성골할수 있는것만 써야한다.
        likeBoard: data?.fetchBoard.likeCount + 1,
      },
      update(cache, { data }) {
        cache.writeQuery({
          query: FETCH_BOARD,
          variables: { boardId: "6170da6cb55052002a93d0f3" },
          data: {
            fetchBoard: {
              _id: "6170da6cb55052002a93d0f3",
              _typename: "Board",
              // _id 와 _typename 이 꼭 있어야 적용이 된다.
              likeCount: data.likeBoard,
            },
          },
        });
      },
    });
  };
  return (
    <>
      <div>좋아요 갯수 : {data?.fetchBoard.likeCount}</div>
      <button onClick={onClickLike}>좋아요 올리기!!</button>
    </>
  );
}

0개의 댓글