DREAMCARD_후기좋아요_COUNT저장

정소현·6일 전
0

팀프로젝트

목록 보기
45/50
post-thumbnail

도움돼요 기능을 구현한 뒤 도움돼요 횟수를 카운트하여 표시해주는 것이 필요하다고 생각이 되었다.

도움돼요 기능은 supabase reviews table의 likes column에 사용자 아이디를 뒤에 추가하는 방식으로 구현하였다.

구현 기능

  • 도움돼요 횟수를 카운트하여 실시간 반영 표시
  • 도움돼요 횟수가 1000개 이상이면 999+로 표시

supabase에 도움돼요 데이터가 들어오는 형태

  • 맨 처음 후기가 작성되었을 때
    likes column : null
  • 누군가 도움돼요를 눌렀을 때
    likes column : ['사용자아이디','사용자아이디2'..]

나는 reviews 데이터들을 useQuery를 사용하여 상위컴포넌트에서 불러왔고 이를 ReviewCard.tsx에서 props로 받은 상태였다.
또한 도움돼요 기능을 useMutation을 활용하여 추가하고 삭제할 수 있도록 구현하였다.
따라 reviews 데이터들이 바뀔 때마다 queryKey:["reviews"]
데이터가 무효화되고 캐싱되기 때문에 useState나 useEffect를 사용하지 않아도 실시간으로 데이터의 변화를 알 수 있었다.

도움돼요 숫자를 셀 수 있도록 상위 컴포넌트에서 로직 작성

const getLikeCount = (likes: string | string[] | null | undefined) => {
    // likes가 null, undefined, 빈 배열인 경우 0 반환
    if (!likes || (Array.isArray(likes) && likes.length === 0)) {
      return 0;
    }
 
    // likes가 문자열일 경우 쉼표로 분리하고 빈 문자열 필터링
    if (typeof likes === 'string') {
      const splitLikes = likes.split(',').filter((like) => like.trim() !== '');
      return splitLikes.length;
    }

    // likes가 배열인 경우 길이 반환
    const likesLength = Array.isArray(likes) ? likes.length : 0;
    return likesLength >= 1000 ? '999+' : likesLength;
  };

reviews.map 내에서 getLikeCount를 불러와 review데이터 전달 & props로 ReviewItem.tsx에 카운트 정보 전달

return (
    <div>
      {reviews.map((review) => {
        const user = users?.users.find((u: User) => u.id === review.user_id);

        if (!user)
          return (
            <div
              className='text-center text-[14px] text-gray-300'
              key={review.id}
            >
              사용자를 찾을 수 없습니다.
            </div>
          );

        const isLiked = review.likes?.includes(signedUserId) ?? false;

        const likeCount = getLikeCount(review.likes);
 return (
          <ReviewItem
            key={review.id}
            review={review}
            user={user}
            isExpanded={expandedReview === review.id}
            onToggle={() => toggleContent(review.id)}
            onNavigate={() => handleReviewDetail(review.id)}
            isLiked={isLiked}
            onLikeToggle={() => handleLikeToggle(review)}
            likeCount={likeCount}
          />
        );
      })}
    </div>

ReviewItem.tsx에서 props로 받아온 count횟수 도움돼요에 함께 표시

const ReviewItem = ({
  review,
  user,
  isExpanded,
  onToggle,
  onNavigate,
  onLikeToggle,
  isLiked,
  likeCount,
}: {
  review: Review;
  user: User;
  isExpanded: boolean;
  onToggle: () => void;
  onNavigate: () => void;
  onLikeToggle: () => void;
  isLiked: boolean;
  likeCount: number | string;
  return (
    ~~~
    ~~~
<span className={`${isLiked ? 'text-white' : ''}`}>도움돼요({likeCount})</span>
            </button>
          </>
        )}
      </div>
)

💥 Trouble Shooting

🔥 문제점
: 데이터가 빈 배열인데도 도움돼요가 1개가 있다고 뜨는 현상

☘️ 해결방법
: supabase에서 데이터가 도움돼요를 눌렀다가 삭제하였을 때
likes column : '[]' 로 들어오는 것을 발견하였고 이것이 length로 체크가 되었다.

likes 데이터가 '[]'일 때 0을 반환하도록 조건 추가

if (likes === '[]') return 0;

supabase에 도움돼요 데이터가 들어오는 형태 - case추가

  • 도움돼요를 눌렀다가 취소하였을 때 (도움돼요를 누른 사람이 0명일 때)
const getLikeCount = (likes: string | string[] | null | undefined) => {
    // likes가 null, undefined, 빈 배열인 경우 0 반환
    if (!likes || (Array.isArray(likes) && likes.length === 0)) {
      return 0;
    }
    if (likes === '[]') return 0; // 추가 
    // likes가 문자열일 경우 쉼표로 분리하고 빈 문자열 필터링
    if (typeof likes === 'string') {
      const splitLikes = likes.split(',').filter((like) => like.trim() !== '');
      return splitLikes.length;
    }

    // likes가 배열인 경우 길이 반환
    const likesLength = Array.isArray(likes) ? likes.length : 0;
    return likesLength >= 1000 ? '999+' : likesLength;
  };

해결완료

0개의 댓글