React

[react-query] 좋아요 낙관적 업데이트

hyriver(강화영) 2025. 9. 29. 20:16

 

api요청을 한 후 새롭게 적용된 데이터를 보여줘야할 때, 우리가 생각하는 것보다 늦게 데이터가 반영된다.

이를 해결하기 위해 api 요청을 하면서 ui를 미리 반영하는 낙관적 업데이트라는 것을 한다.

 

대표적인 예로 좋아요 클릭 시 하트 색 또는 좋아요 개수를 변경시키는 것이 있다.

 

(gif가 좀 이상하게 잘려서 아다리가 안맞음 ㅠ;) 이렇게 좋아요를 클릭해도 숫자가 늦게 반영이 되는 상황에서 낙관적 업데이트를 사용하면 좋아요를 클릭 시 개수를 바로 반영시킬 수 있다.

 

 

낙관적 업데이트 방법

(두둥)

 

일단 나는 react-query를 사용하고 있고, 좋아요 클릭 시 post 요청을 보내고 있다.

 

1. useMutate의 onMutate에서 변경하고자 하는 쿼리를 queryClient.cancelQueries 한다.

좋아요 버튼을 클릭하면서 동일한 쿼리의 데이터가 요청될 수 있다. 이 경우 낙관적 업데이트한 데이터를 덮어씌울 수 있으므로(race condition) 그 요청 결과가 캐시를 덮어씌우지 못하도록 막는다.

onMutate: async () => {
  await queryClient.cancelQueries({ queryKey: ['comment', idx] });

 

 

2. queryClient.getQueryData로 해당 쿼리 데이터를 받는다.

const cache = queryClient.getQueryData(['comment', idx]);

 

 

3. 캐시에 map을 돌려 같은 idx의 경우 좋아요 값과 개수 값을 변경해준다.

      const copy = cache?.map(i => {
        if (i.IDX === IDX) {
          return {
            ...i,
            IS_LIKE: !prevIsLike ? 1 : 0,
            LIKE_CNT: !prevIsLike ? i.LIKE_CNT + 1 : i.LIKE_CNT - 1,
          };
        }
        return i;
      });

 

 

4. 변경한 copy 데이터를 queryClient.setQueryData에 넣어준다. 그리고 캐시데이터를 onMutate에서 리턴해준다. 이 리턴해준 데이터는...

      queryClient.setQueryData(['comment', idx], { copy });
      
      return { cache };
}

 

 

5. onError의 context에 담기게 된다. 만약 에러가 날 경우 onError에서 setQueryData로 context의 해당 데이터를 가져다 사용하여 롤백되도록 한다.

    onError: (err, _, context) => {
      if (context?.cache) {
        queryClient.setQueryData(['comment', idx], context.cache);
      }
    },

 

 

 

이렇게 낙관적 업데이트를 한 후의 결과

 


흐린눈을 하려면 할 수 있는 사항이지만 좋은 UX를 위해서는 이런 사소한 디테일을 챙기는 것 또한 중요한 것 같다