[Main Project] UDog / 구현하기 - 좋아요 개수, 무한 렌더링 에러

soohyunee·2023년 3월 30일
0

[Main Project] UDog

목록 보기
15/18

1. 구현하기

진행 상황

  • 서비스 설명서, 기술발표 영상 제작
  • 스타일북 좋아요 개수 추가

진행 예정

  • https로 재배포

2. TIL

2-1. 좋아요 개수 추가하기

상태 변화로 인한 중복 데이터

원래 스타일북에는 좋아요 개수가 없었다. 좋아요 개수를 추가하면 좋겠다는 팀원분의 의견을 수렴하여 스타일북에도 좋아요 개수를 같이 보여주게끔 구현했다.
스타일북은 미용실 상세 페이지와는 다르게 개별 페이지가 없고 페이지와 사이즈에 해당하는 데이터 개수 만큼 한번에 데이터가 받아와진다.

시도한 방법

useEffect를 활용하여 like의 상태가 바뀔 때마다 다시 get 요청을 하려고 했었다. 하지만 미용실 상세페이지와는 달라서 해당 get 요청은 페이지와 사이즈 값이 필요한데 이것을 어떻게 나타내야할지가 막막했다.
그래서 이 방법은 더 이상 방법이 없을 것 같아서 다른 방법으로 해결하였다.

useEffect(()=>{
  API.get(`${url}?page=${page}&size=${perPage}`)
},[like])

해결 방법

미용실 상세페이지에서는 좋아요 개수를 업데이트 해주는 부분이 좋아요 버튼 커스텀 훅에서 post와 delete 부분에 then으로 다시 get 요청을 해주게끔 작성되어있다. 스타일북 좋아요 버튼 커스텀 훅에서 마찬가지로 좋아요 개수를 상태로 관리한 후 set함수를 통해 다시 get 요청을 하는 것이 아니라 post면 +1 delete면 -1을 해주고, likeCount을 반환시키고 그것을 렌더링 해주는 로직으로 해결할 수 있었다.

function useReviewLike(id, like, styleLikeId, styleLikeCount) {
  const [likeCount, setLikeCount] = useState(styleLikeCount);
  if (!like) {
      API.post(
       // 좋아요 버튼 로직
       ).then((res) => {
         setParam(res.data.styleLikeId);
         setLikeCount(likeCount + 1);
      }) 
      // 이후 로직 동일
  	} else {
      API.delete(
      // 좋아요 취소 로직
	).then(()=>{
        setLikeCount(likeCount - 1);
      })
     // 이후 로직 동일   
  }  
  return { onLikeButtonClick, likeCount };
}

2-2. 무한 렌더링 에러

리뷰에서의 무한 렌더링 에러

팀원이 맡으신 리뷰 부분에서 기능이 잘 작동하는 것 같아 보였는데 개발자 도구를 열어보니 아무런 상태 변화가 없었는데도 불구하고 무한 렌더링이 발생하고 있다는 것을 알게되었다.

알고보니 useEffect 부분에서 수정을 했을 때 상태를 즉시 업데이트를 해주기 위해서 의존성배열에 reviews를 전달하면서 무한 렌더링이 발생하였다. 겉으로 봤을 때는 수정한 후 즉시 상태가 반영된 것 처럼 보이지만 계속 get요청을 받아오고 있는 것과 마찬가지여서 그렇게 보였던 것이었다. 추후에 성능 문제가 있을 것 같아 수정을 맡기로했다.

  const [currentPage, setCurrentPage] = useState(1);
  const reviews = useSelector(selectReviews);

  useEffect(() => {
    dispatch(fetchReviews(currentPage));
  }, [dispatch, currentPage, reviews]);

시도한 방법

reviews가 아닌 reviews.reviewText로 의존성 배열을 변경해주었다. 하지만 제대로 작동하지 않았다. console.log(reviews.reviewText)를 해보니 undefined만 나오고 있었다. reviews가 배열로 이루져있고, 배열 안에는 객체가 담겨있는데 그 객체안에 reviewText가 있었기 때문에 이 방법으로는 접근 할 수가 없었다.

  const text = reviews.reviewText;
  useEffect(() => {
    dispatch(fetchReviews(currentPage));
  }, [dispatch, currentPage, text]);

해결 방법

리뷰 수정이 현재 모달과 연결되어있고, 모달의 수정하기 버튼에는 patch 요청이 연결되어있었다. 이 patch 요청도 리뷰의 상태를 관리하고 있는 리덕스 파일에서 createAsyncThunk를 활용하여 비동기적으로 리뷰를 수정하는 액션을 작성하고자 했다.
그리고 addCase 메서드를 사용하여 patchReviews.fulfilled 케이스를 추가하고, 이 케이스에서는 state.reviews 배열에서 수정된 리뷰를 찾아 업데이트한다. 이때, map 함수를 사용하여 review.reviewId가 수정된 리뷰의 식별자와 일치하는 경우 새로운 객체로 바꾸어 리뷰 내용을 수정하고, 그렇지 않으면 리뷰 객체를 그대로 반환하는 로직을 추가해주었다.

export const patchReviews = createAsyncThunk(
  'reviews/patchReview',
  async ({ reviewId, reviewText }, { dispatch }) => {
    try {
      const response = await API.patch(`${REVIEW_ENDPOINT}/${reviewId}`, { reviewText }, config);
      dispatch(setSuccess('수정 성공'));
      return response.data;
    } catch (error) {
      dispatch(setError('수정 실패'));
      throw error;
    }
  },
);

extraReducers: (builder) => {
    builder
  		.addCase(patchReviews.pending, (state) => {
        state.status = 'loading';
      })
      	.addCase(patchReviews.fulfilled, (state, action) => {
        state.status = 'succeeded';
        state.reviews = state.reviews.map((review) =>
          review.reviewId === action.payload.reviewId
            ? { ...review, reviewText: action.payload.reviewText }
            : review,
          );
       })
      	.addCase(patchReviews.rejected, (state, action) => {
        state.status = 'failed';
        state.error = action.error.message;
      });
  },
  const handleSubmit = (event) => {
    event.preventDefault();
    dispatch(patchReviews({ reviewId, reviewText }));
    dispatch(closeModal());
  };
profile
FrontEnd Developer

0개의 댓글