망고 프로젝트 : useInfiniteQuery + Optimistic Update (React Profiler를 사용하여 성능 측정)

728x90
반응형

1. 좋아요 버튼: 하트 10번 계속 클릭하기 (Optimistic Update 사용)

적용 전 (옵티미스틱 업데이트 적용 x)  / 적용 후 ( 옵티미스틱 업데이트 적용 o)

* Priority : Normal ➡️ Immediate

* Commited at :  0.5 s ➡️ 1.8 s

* Render : 38.5 ms ➡️17.4 ms

* Layout effects : 8.2 ms ➡️ 0.2 ms

* Passive effects : 2 ms ➡️ 0.6 ms

 

 

2. 카테고리 - 습관 인증

적용 전 (습관 인증) / 적용 후 ( 습관 인증)

 

* Render : 41.8 ms ➡️26.8 ms

* Layout effects : 6 ms ➡️ 3.7 ms

* Passive effects : 2.2 ms ➡️ 1.7 ms

 

 

3. 카테고리 - 전체보기

적용 전 (전체보기) / 적용 후 (전체보기)

* Render : 45.7 ms ➡️ 29.9 ms

* Layout effects : 4.8 ms ➡️ 3.7 ms

* Passive effects : 2.7 ms ➡️ 1.8 ms

 

 

[변경 사항]

1. useInfiniteQuery 조회 형태 변경 

(1) 목적 : 더 보기 기능으로 데이터 가져올때 부하 줄이기

 

(2) 변경 필요 : 좋아요 기능을 optimistic update를 하기 위해서는 구조 변경 필요

 

(3) 변경 전

: queryFn : querySnapshot.docs 리턴

=> 좋아요 기능 queryClient.setQueryData <InfiniteData<PostType[]>>으로 가져오는 oldData 형태 문제

=> oldData : QueryDocumentSnapshot 구조

=> getData: pages.flat()하여 map으로 doc.data()를 하여 데이터를 가공

=> updateData : 원하는 데이터 (좋아요 버튼: isLiked 값 변경)

=> return : updateData를 대입하려고 했으나, 다시 QueryDocumentSnapshot 구조로 변경해야할 것 같음

=> 현재 사용되는 oldData의 구조를 변경하기 위해서는 useInfiniteQuery 구조를 변경해야함!

(oldData : QueryDocumentSnapshot 구조 x / 데이터 형식의 객체 o)

 

(▼Optimistic Update 구현하려고 시도했으나 안 되던 코드 ▼ )

queryClient.setQueryData<InfiniteData<PostType[]>>
		([QUERY_KEYS.POSTS, category], (oldData) => {
      
        let getData = oldData?.pages.flat().map((doc) => {
          const postData = doc.data();
          return {
            id: doc.id,
            isLiked: postData.likedUsers?.includes(auth.currentUser?.uid || ''),
            ...postData
          };
        });

        const updateData = getData?.map((post) => {
          if (post.id === selectedPostId) {
            return {
              ...post,
              isLiked: !post.isLiked
            };
          } else {
            return post;
          }
        });

        return {
          pages: oldData?.pages ?? [],
          pageParams: oldData?.pageParams ?? []
        };
      });

 

 

(4) 변경 후

: queryFn : querySnapshot.docs ➡️ posts.push({ id: doc.id, ...postData, isLiked: isLiked, snapshot: doc }); 리턴

=> oldData : 데이터 형식의 객체로 가져오기

=> 특이한 점은, map을 2번 사용해야한다

useInfiniteQuery는 2가지의 배열로 구성된 객체|

(1) pages 배열 ( 각 페이지에 대한 데이터 갖고 있음 )

(2) pageParams 배열  ( 각 페이지를 불러올 때 사용된 매개변수를 갖고있음 )

 queryClient.setQueryData<InfiniteData<PostTypeFirebase[]>>([QUERY_KEYS.POSTS, category], (oldData) => {
        if (!oldData) return oldData;

        const updateData = oldData?.pages.map((pagesPost) => {
          return pagesPost.map((post) => {
            const newLikeCount = post.isLiked ? post.likeCount - 1 : post.likeCount + 1;
            if (post.id === selectedPostId) {
              return {
                ...post,
                isLiked: !post.isLiked,
                likeCount: newLikeCount
              };
            } else {
              return post;
            }
          });
        });

        return {
          ...oldData,
          pages: updateData
        };
      });

=> 원래의 'oldData'객체를 스프레드 연산자를 사용해서 복사하고

이 복사된 객체의 'pages'속성을 'updateData' (좋아요 숫자 , 좋아요 여부)로 적용해서

새로운 InfiniteData 객체 반환.

 

 

[체크 사항]

조회 & 좋아요 기능에 맞게 변경했기에, 기존에 잘 동작하던 부분도 같이 테스트하기

➡️ prefetch 한 부분 

➡️ 새 글 작성 후 카테고리 이동시 오류 발생 (썸네일 undefined 오류)

➡️ 디테일 페이지에서 댓글 작성 후 커뮤니티 페이지에 반영 안 됨 (queryKey의 invalidateQueries 변경)

 

 

 

끝.

반응형