[Main Project] UDog / 구현하기 - 좋아요 기능 구현하기

soohyunee·2023년 3월 24일
0

[Main Project] UDog

목록 보기
12/18
post-thumbnail

1. 구현하기

진행 상황

  • 로고 만들기
  • 서비스 소개 페이지

진행 예정

  • 예약 API 연결
  • 팀원 도와주면서 개발 마무리하기

2. TIL

2-1. 스타일북 좋아요 기능

StylebookItem.js

스타일북은 상세페이지가 따로 없고 전체 페이지에서 StylebookItem 컴포넌트마다 좋아요 기능이 있다. 좋아요 버튼은 토글형식으로 초기값은 빈 하트이고, 로그인한 유저만 좋아요 버튼을 누를 수 있게 구현하였다.
로그인을 하면 좋아요 버튼의 상태에 맞게 하트가 빈 하트와 꽉 찬 하트로 보이게 되고 이때 하트의 상태는 likeId가 0인지 아닌지에 따라 판별하게 된다. 만약 likeId가 0이라면 빈 하트가 보이게 되고, 0이 아니라면 꽉 찬 하트가 보이게 되는 것이다. 로그인 안한 유저는 likeId의 값이 0이기 때문에 빈 하트만 보이게 된다.

  const likeId = style.styleLikeId;
  const [like, setLike] = useState(likeId);

  {like ? (
     <IoHeart className="icon" onClick={handleLikeClick}/>
   ) : (
     <IoHeartOutline className="icon" onClick={handleLikeClick} />
  )}

좋아요 버튼을 누르면 우선 로그인 한 유저인지 아닌지 먼저 판별을 하게 된다. 로그인 하지 않은 유저라면 로그인 하러가기 라는 모달창을 띄운다.
로그인 한 유저라면 useState로 like의 상태를 관리하고 있기 때문에 누를 때 마다 like의 상태가 true / false로 바뀌게 된다. 그리고 좋아요 기능을 작성해둔 커스텀훅의 함수가 실행되게 된다.

  const handleLikeClick = () => {
    if (!user) {
      dispatch(
        openModal({
          modalType: LOGINMODAL,
          isOpen: true,
        }),
      );
      return;
    }
    setLike(!like);
    onLikeButtonClick();
  };

likeSlice.js

likeSlice에서는 onLikeButtonClick 함수의 API의 중복 요청을 막기위해서 isSubmit의 상태를 관리하고자 리듀서를 작성해두었다. 초기값은 false로 두고 onLikeButtonClick 함수가 실행될 때마다 dispatch로 실행시켜 true로 바꾸어주고 요청이 끝나면 false로 다시 바꾸어 주었다.

const initialState = {
  isSubmit: false,
};


const likeSlice = createSlice({
  name: 'like',
  initialState,
  reducers: {
    setIsSubmit: (state, action) => {
      state.isSubmit = action.payload;
    },
  },
});

useReviewLike.js

우선 useReviewLike는 파라미터로 id, like, styleLikeId를 받고 있다. 그리고 커스텀훅 안에 onLikeButtonClick 함수가 작성되어있다. 우선 isSubmit의 상태가 true라면 함수를 종료 시키고, false일 때만 실행되게 해주었다.
그리고 like의 상태에 따라 like가 false라면 post요청이, true라면 delete요청이 가도록 분기해주었다.

 const { onLikeButtonClick } = useReviewLike(style.reviewId, like, likeId);
if (!like) {
      API.post(
       // post 요청 작성
     )   
  } else {
     API.delete(
       // delete 요청 작성
     )
  }

하지만 post 요청시에는 Path Variable과 요청 바디로 reviewId를 보내주면 응답으로 LikeId를 받게 되는데 post 요청 바디로 변경된 LikeId의 상태가 저장이 되지 않아 delete할때 Path Variable로 전달된 LikeId는 변경되기 전의 LikeId여서 에러가 발생했다.

그래서 LikeId를 업데이트할 수 있는 useState를 만들어서 post 요청 바디로 받게되는 LikeId를 상태변경함수로 변경 시켜주니 해당 에러가 해결됐다.

const [param, setParam] = useState(styleLikeId);

// post 요청 작성
.then((res) => {
   setParam(res.data.styleLikeId);
  })
 } else {
   API.delete(`${STYLELIKE_ENDPOINT}/${param}`)

2-2. 미용실 좋아요 기능

likeSlice.js

미용실 좋아요 기능은 상세페이지의 Home 탭에서 실행할 수 있게 구현했다. HomeTab 컴포넌트는 위와 비슷하게 구현되었지만 상세페이지를 이동할 때마다 상세페이지의 likeId와 likeCount를 다시 불러와야 해서 likeSlice에 likeId와 likeCount를 리듀서를 추가로 작성해두었다.

const initialState = {
  likeId: 0,
};

const likeSlice = createSlice({
  name: 'like',
  initialState,
  reducers: {
    setLikeId: (state, action) => {
      state.likeId = action.payload;
    },
    setLikeCount: (state, action) => {
      state.likeCount = action.payload;
    },
  },

HomeTab.js

그리고 새로운 상세페이지에 진입하여 새로운 get 요청이 있을 때마다 useEffect 훅을 사용해서 저장한 likeId와 likeCoun를 dispatch로 다시 업데이트를 시켜주고 useState로 버튼의 상태를 변경시켜주었다.

 const { likeId } = useSelector(selectLike);
 const [like, setLike] = useState(likeId);
 const shop = useFetch(`${HAIRSHOP_ENDPOINT}/${id}`);

  useEffect(() => {
    if (shop) {
      dispatch(setLikeCount(shop.likeCount));
      dispatch(setLikeId(shop.hairShopLikeId));
      setLike(shop.hairShopLikeId);
    }
  }, [shop]);

like의 상태를 꺼내서 부분에 위와 같이 적용 시켜주고, likeCount의 상태를 홈탭 컴포넌트에 꺼내서 좋아요 개수가 들어가야 하는 부분에 적용시켜 주었다.

const { likeCount } = useSelector(selectShop);

{likeCount ? likeCount.toLocaleString() : likeCount}

useShopLike.js

useShopLike 커스텀훅은 위와 다르게 파라미터로 id, like만 받는다. likeId는 slice 파일의 상태를 꺼내쓰기 때문이다. post와 delete를 like 상태에 따라 분기하는 것은 비슷하다. 하지만 useShopLike에서는 likeId를 리덕스로 관리하기 때문에 post요청의 응답 바디로 받은 새로운 likeId를 dispatch로 상태를 업데이트 시켜주어야 했다.
그리고 좋아요의 개수도 업데이트 해주어야 하기 때문에 dispatch로 likeId의 상태를 업데이트 시켜주면서 다시 get 요청하고 likeCount를 dispatch로 업데이트 시켜주었다.

 const getLikeCount = () => {
    API.get(`${HAIRSHOP_ENDPOINT}/${id}`, { headers: headers }).then((res) =>
      dispatch(setLikeCount(res.data.likeCount)),
    );
  };


// post 요청
.then((res) => {
 	dispatch(setLikeId(res.data.hairShopLikeId));
    getLikeCount();
 })
profile
FrontEnd Developer

0개의 댓글