Optimistic UI: 빠르게 할 수 없다면, 속여보자! ㅋㅋ

2023. 7. 14. 08:02Next.js

728x90
반응형

Optimistic UI

  • 유저가 네트워크 응답을 기다려야 할 때, 예상 응답을 미리 표시해주어 지연을 숨기는 방법이다.
  • 전제 조건
    실패할 가능성이 낮고, 실패해도 문제가 없는 상황에 적용해야한다.
  • 배제해야 하는 경우
    여러 테이블에 데이터를 함께 저장하는 경우. 👉하나라도 실패하면 전체 API가 실패로 처리되기 때문에 실패 확률이 높기 때문

 

활용 예시: 좋아요 프로세스

일반적인 방식

브라우저에서 좋아요를 누르면 백엔드에 `좋아요 API`를 요청하고 DB에 접근해서 기존의 좋아요 수에 +1을 한다.
DB에서 돌려받은 값을 백엔드를 거쳐 브라우저에서 받아서 화면에 보여준다.

 

👇🏻 Optimistic UI를 적용하면 ~

  1. state에 좋아요의 값을 +1 해놓고 state를 화면에 먼저 보여준다.
  2. 실제 요청의 결과가 도착하면 실제 데이터로 교체한다. (1에서 변경한 값과 일치한다면 유지!)

결제처럼 중요한 데이터가 아니고 && 실패할 가능성이 낮은 경우에
이런 눈속임으로 더 빠른 사용자 경험을 제공할 수 있다.


 

좋아요 프로세스의 결과를 화면에 보여주는 방법 세가지 비교

  1. 결과를 result에 받고, state에 담아서 화면에 보여주는 방법
  2. refetchQueries로 다시 받아오는 방법
    (mutation 한 번, query 한 번, 요청을 총 두 번 하게 된다.👎)
       /* refetch - api가 LIKE_BOARD 한 번, FETCH_BOARD 한 번 해서 총 두 번 요청된다. */
       refetchQueries: [
         {
           query: FETCH_BOARD,
           variables: { boardId: "6269ecf7a8255b002988d65e" },
         },
       ],
  3. cacheState를 직접 수정하는 방법
    optimisticResponse를 같이 쓸 수 있다. 👏👏

3번 방법을 이용하면 1,2번 방법을 이용했을 때보다 속도가 훨씬 빠르다!!

 

 


 

Optimistic UI 활용하기

1. optimisticResponse

mutation 함수 안에 optimisticResponse 를 써서 API 응답이 오기 전에 보여줄 값을 지정한다.

      optimisticResponse: {
        likeBoard: (data.fetchBoard.likeCount || 0) + 1,
          // 기존의 좋아요 수 + 1
          // undefined일 때는 0 + 1
      },

2. update

실제로 응답이 도착하면, update 함수를 이용해서 cacheState의 값을 직접 바꿔준다.

(update 함수는 mutation이 완료되어 서버에서 응답을 받았을 때 호출된다.)

      update(cache, { data }) {
        // data는 likeBoard API의 response로 받는 값이다.
        cache.writeQuery({
          // 기존의 데이터를 직접 바꾼다.
          query: FETCH_BOARD, // 바꿀 쿼리
          variables: { boardId: "6269ecf7a8255b002988d65e" }, 
          // 위에서 useQuery 선언할 때 쓴 쿼리명과 variables를 그대로 똑같이 써야 한다.
          data: {
            // 조작할 것을 적는다. 여기서는 data를 조작한다.
            fetchBoard: {
              _id: "6269ecf7a8255b002988d65e",
              __typename: "Board", 
              // id와 typename은 조건이다.
              // 이 두개의 조건을 가지고 globalState에 저장된 것에서 찾아내기 때문에 id와 typename은 둘 다 꼭~ 입력해야 한다.
              // likeCount:10, // 요로케 입력하면 기존에 fetch해온 값을 무시하고 여기에서 입력한 10이 된다. 
              // (백엔드의 값과는 상관 없이 조작만 하는 것이다.)
              likeCount: data.likeBoard, // data.likeBoard : likeBoard의 결과이다.
            },
          },
        });
      },

 

728x90
반응형