[React] optimustic ui

임동현·2022년 5월 1일
0

옵티미스틱 UI

기존의 UI 인터랙션

우리가 자유게시판 상세보기에 '좋아요' 버튼을 누를 때 의 동작을 생각해봅시다.

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

좋아요 버튼 하나 클릭했을 뿐인데, 사용자는 결과를 얻기까지 기다려야합니다. 또한 몰입하고 있는 상태를 방해하게 됩니다.

Optimustic UI

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

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

오류가 발생했을 경우
성공할거라고 예상 했는데 , 서버에서 뒤늦게 에러가 났다는 응답이 오면 어떻게 하나요 ?

!!!: 조용히 원래 상태로 되돌립니다.

중고마켓에서 찜하기 버튼을 생각해 봅시다.

  1. 사용자가 찜하기 하트 버튼을 누른다.
  2. 하트 색상이 바뀌면서 찜이 되었음을 바로 알려준다.
  3. 서버에 요청한다.
  4. 서버에서 실패했다는 응답을 받는다.
  5. 조용히 찜하기 버튼의 하트색깔을 변경한다.

이렇게 함으로써 에러가 났다는 경고창으로 인해 사용자는 뜬금없이 방해받을 일도 없고 , 색상이 다시 변경 되었기 때문에 다시 시도 해야겠다는 생각을 자연스럽게 하게 됩니다.

gql적용해보기

그래프큐엘 에서는 mutation 을 할 때 OptimisticResponse 라는 옵션을 제공합니다.

import { useMutation, useQuery, gql } from "@apollo/client";

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() {
    const { data } = useQuery(FETCH_BOARD, {
        variables: { boardId: "6267af69a8255b002988cc79" },
    });

    const [likeBoard] = useMutation(LIKE_BOARD);

    const onClickOptimisticUI = () => {
        // 버튼 누르면 뮤테이션 실행
        likeBoard({
            variables: { boardId: "6267af69a8255b002988cc79" },

            // 방법 1. state 활용

            // 방법 2. 쿼리 두 번
            // refetchQueries: [
            //   {
            //     query: FETCH_BOARD,
            //     variables: { boardId: "6269ece4a8255b002988d633" }
            //   }
            // ]

            optimisticResponse: {
                likeBoard: (data?.fetchBoard.likeCount || 0) + 1, // undefined면 0 + 1 해줘~!
            },
            // 3. 캐시(글로벌 스테이트)를 직접 수정 -> optimisticResponse와 같이 사용 가능
            update(cache, { data }) {
                cache.writeQuery({
                    query: FETCH_BOARD,
                    variables: { boardId: "6267af69a8255b002988cc79" },
                    data: {
                        fetchBoard: {
                            // 공식처럼 입력하는 것 두 가지(_id, __typename). 나머지는 옵션.
                            _id: "6267af69a8255b002988cc79",
                            __typename: "Board",
                            likeCount: data.likeBoard,
                        },
                    },
                });
            },
        });
    };

    return (
        <>
            <h1>Optimistic-UI</h1>
            <div> Like 카운트: {data?.fetchBoard.likeCount}</div>
            <button onClick={onClickOptimisticUI}>좋아요 + 1</button>
        </>
    );
}
  1. likeCount: data.likeBoard update 함수가 실행이 될때 우리가 optimisticresponse 에 적은 내용이 아폴로 클라이언트 캐시에 optimistic 버전으로 따로 저장합니다.

  2. 아폴로 클라이언트는 이를 알아차려 저장된 데이터를 가지고 연관된 컴포넌트들을 다시 랜더링 합니다. 이 부분은 네트워크 욫어이 필요없기 때문에 사용자들에게 거의 바로 반영됩니다.

  3. 서버의 응답으로 진짜 데이터를 받으면 , 아폴로 클라이언트는 기존의 optimistic 버전을 지우고 서버에서 받은 데이터를 저장합니다.

  4. 아폴로 클라이언트는 다시 이를 알아차리고 연관된 컴포넌트를 다시 랜더링 합니다.

profile
프론트엔드 공부중

0개의 댓글