본문 바로가기
매일 해내는 개발/Develog

[Develog] 좋아요 기능 optimistic update로 구현하기

by 해야지 2023. 3. 22.
반응형

react query의 mutate로 optimistic update 구현하기!

개발 기간 동안에도 계속 optimistic update로 구현하고 싶었으나 잘 풀리지 않아서 보류하고 있었던 부분이다.

또 며칠 씨름했었는데 이걸 왜 헤맸지 싶을 정도로 간단하게 해결했다........

왜 헤맸지 진짜? 그래도 결국 내가해냄 하는 마음이 들어 뿌듯했다.

 

[Develog] 좋아요 기능 구현2

이전 글 [Develog] 좋아요 기능 구현(with firebase, useQuery, useMutation) 현재 데이터 구조상 모든 게시글을 저장하는 post 컬렉션(문서는 각 게시글 데이터)과 내가 좋아요한 게시글이 저장되는 myprojects 컬

subtlething.tistory.com

기존에 useState를 사용해 수동으로 optimistic update를 구현했는데, react query를 잘 사용하면 그럴 필요가 없었다.

낙관적 업데이트의 개념과 사용방법은 아래의 링크를 참고하기 바란다.

 

[React] optimistic update(낙관적 업데이트)

React Query는 API 호출과 관련된 데이터를 캐시하고 관리하는 라이브러리이다. 이 라이브러리는 optimistic updates(낙관적 업데이트)를 지원하며, 이는 데이터를 서버로부터 성공적으로 업데이트하기

subtlething.tistory.com

 

optimistic update의 핵심은 서버의 응답을 기다리지 않고 UI를 변경해주는 것이다.

이 때 변경전 데이터를 저장해두고 만약 오류가 발생했을 때는 저장해둔 변경 전 데이터로 롤백해주는 것이다.

▶️ 방법

useState로 선언했던 부분을 let 변수로 수정해준다. 이후에 값들이 변경돼야하므로 const가 아닌 let으로 선언해준다.

useMutation부분에 onMutate 함수를 추가한다.

onMutate는 mutation이 시작되기 전에 호출되어 mutation의 실행 전 상태를 기록하거나 업데이트하는 데 사용한다.

롤백을 위한 이전 값을 previousProjectLike에 저장해 두고 setQueryData를 통해 상태를 업데이트해준다.

onError 함수에서는 에러가 발생했을 경우 이전 값으로 데이터를 다시 set해준다.

  let countLike = projectLike?.like;
  let isLike = myProjects?.likedProjects.includes(pid);

  const queryClient = useQueryClient();
  const { mutate: updateLikeMutate } = useMutation(
    () => updateLike(pid, countLike),
    {
      onMutate: async () => {
        await queryClient.cancelQueries(['post', pid]);
        const previousProjectLike = queryClient.getQueryData(['post', pid]);
        queryClient.setQueryData(['post', pid], () => {
          isLike ? (countLike -= 1) : (countLike += 1);
        });
        return { previousProjectLike };
      },
      onError: (err, variables, context) => {
        queryClient.setQueryData(['post', pid], context?.previousProjectLike);
      },
      onSettled: () => {
        queryClient.invalidateQueries(['post', pid]);
      },
    },
    
    
  const { mutate: updateMyProjectMutate } = useMutation(
    () => updateMyProject(uid, pid, isLike),
    {
      onSuccess: () => {
      onMutate: async () => {
        await queryClient.cancelQueries(['myProjects', uid]);
        const previousMyProjects = queryClient.getQueryData([
          'myProjects',
          uid,
        ]);
        queryClient.setQueryData(['myProjects', uid], () => {
          isLike = !isLike;
        });
        return { previousMyProjects };
      },
      onError: (err, variables, context) => {
        queryClient.setQueryData(
          ['myProjects', uid],
          context?.previousMyProjects,
        );
      },
      onSettled: () => {
        queryClient.invalidateQueries(['myProjects', uid]);
        queryClient.invalidateQueries(['post', 'mostViewed']);
        queryClient.invalidateQueries(['post', 'mostLiked']);
    },
  );
반응형

댓글