min

Optimistic Updates (by React-query) 본문

리엑트/성능 개선

Optimistic Updates (by React-query)

minprogramming 2023. 12. 16. 16:26

1. Optimistic Updates의 정의

 : Optimistic Updates는 "요청을 보내기 전에 요청에 대한 결과를 예상 및 적용하고 요청을 보낸 후에 예상된 결과를 UI에 반영하는 것"을 의미한다. 이 문장을 보고 바로 이해되기에는 추상적으로 다가올 것이다. 그래서 이 과정을 크게 request 전 / 후로 나눠서 설명하고자 한다.

  • request 전 : request 후에 결과를 예측해서 request 요청을 받기 전에 해당 요청 값을 미리 변화시키는 것이다.  (새로고침시 없어짐)
  • request 후 : request 후에는 request전에 적용한 값을 요청 받은 값으로 바꾼다. (새로고침시 유지됨)

여기까지 살펴본다면 Optimistic Updates의 대략적인 흐름은 이해가 될 것이다. 그렇다면 왜 이렇게 복잡한 로직을 통해서 Optimistic Updates를 구현하고자 하는 걸까? 그 이유에 대해서 쳅터 2에서 살펴보려고 한다.

 

2. Optimistic Updates의 필요한 이유

 : Optimistic Updates가 필요한 이유를 살펴보기 위해서 실제 예시를 하나 준비했다. 만약 좋아요 관련된 기능을 구현하고자 한다고 하자

이때 광클릭을 막기 위해서 좋아요를 눌렀을 때 서버까지 전달되는데 있어서 일정 delay가 발생한다고 하자. 마지막으로 좋아요를 눌렀을 때 서버에게 요청을 보내고 응답 데이터를 통해서 좋아요를 업데이트 한다고 하자. 이 예시를 시뮬레이션 해본다면 좋아요를 누르면 일정 딜레이 후에 좋아요가 활성화 될 것이다. 이는 UI / UX 측면에서 봤을 때 좋은 방법이 아니다. (일정 딜레이 동안 유저는 자신이 좋아요를 성공적으로 눌렀는지를 확인할 수 없음.) 그렇기 때문에 우리는 이 과정을 변화시킬 필요가 있다. 그리고 이 변화시키는 방법이 바로 Optimistic Updates 인 것이다. 그렇다면 앞서 설명한 정의를 어떤 방식으로 구현할까? 그 방법에 대해서 쳅터 3에서 살펴보려고 한다.

 

3. Optimistic Updates by React-query 의 사용 방법

// 실행 환경
// 1. useMutation을 사용하고 있다.
// 2. queryKey로는 ["posts" , posts.id]이다. (게시글 단건 조회)
// 3. 좋아요 관련 api 명은 updateHeart이다.

useMutation(updateHeart , {
	onMutate: async (newPost) => {
        // 보내는 도중에 refetch를 막기 위해서 cancelQuries를 사용했다.
        await queryClient.cancelQueries({ queryKey: ['posts', newPost.id] })

        // 내가 바꾸고자 하는 데이터를 선별하기 위해서 getQueryData를 사용했다.
        const previousPost = queryClient.getQueryData(['posts', newPost.id])

        // 새로운 값으로 Optimistically update를 한다.
        queryClient.setQueryData(['posts', newPost.id], newPost)

        // Return a context with the previous and new todo
        return { previousPost, newTodo }
  },
  
  onError: (err, newPost, context) => {
    queryClient.setQueryData(
      ['todos', context.newTodo.id],
      context.previousPost,
    )
  },
  onSettled: (newPost) => {
    queryClient.invalidateQueries({ queryKey: ['posts', newPost.id] })
  },
})