'좋아요'를 구현해보자

woori·2024년 8월 21일

Instagram

목록 보기
3/4
post-thumbnail

해당 부분을 postActions 컴포넌트로 분리했다.

import React from "react";
import FavoriteBorder from "@mui/icons-material/FavoriteBorder";
import ChatBubbleOutlineIcon from "@mui/icons-material/ChatBubbleOutline";
import TelegramIcon from "@mui/icons-material/Telegram";
import BookmarkBorderIcon from "@mui/icons-material/BookmarkBorder";
import styles from "../styles/post.module.css";

function PostActions() {
  return (
    <div className={styles.icons_container}>
      <div>
        <FavoriteBorder className={styles.icon} />
        <ChatBubbleOutlineIcon className={styles.icon} />
        <TelegramIcon className={styles.icon} />
      </div>
      <div>
        <BookmarkBorderIcon className={styles.icon} />
      </div>
    </div>
  );
}

export default PostActions;

1. '좋아요' 상태를 저장해보자

아이콘을 클릭하면, handlePostLike 이벤트가 발생한다.

<FavoriteBorder className={styles.icon} onClick={handlePostLike} />

handlePostLike 이벤트 메서드는 다음과 같이 구현했다.

const handlePostLike = async () => {
  try {
    const response = await axios.post('/api/postlike', {
      userId: userId, 
      postId: postId
    });
    console.log(response.data);
  } catch (error) {
    console.error('Error liking the post:', error);
  }
};

데이터베이스에 사용자id포스트id가 정상적으로 저장되는 것을 확인했다.

그런데, 좋아요를 눌러도 icon이 변하지 않았다. 😕

당연하다.
아이콘은 여전히 <FavoriteBorder /> 이거 하나다.


2. '좋아요' 상태를 가져와보자

사용자가 해당 포스트에 좋아요를 눌렀는지 확인하는 메서드를 구현했다.

const [isLiked, setIsLiked] = useState(false);

useEffect(() => {
  const fetchLikeStatus = async () => {
    try {
      const response = await axios.get('/api/postlike/status', {
        params: { userId: userId, postId: postId }
      });
      setIsLiked(response.data);
    } catch (error) {
      console.error('Error fetching like status:', error);
    }
  };

  fetchLikeStatus();
}, [userId, postId]);

setIsLiked(response.data); 에서 응답이 true라면, isLinked = true가 된다.
isLinked = true일때, <FavoriteBorder /> 대신 <FavoriteIcon />가 출력되어야한다.

isLiked ? (
  <FavoriteIcon className={styles.icon} />
) : (
  <FavoriteBorder className={styles.icon} onClick={handlePostLike} />
)}

그러면 이렇게 좋아요 아이콘이 바뀌지 않는다.
여전히 <FavoriteBorder /> 가 출력된다.

모달창을 껐다가 켜야 <FavoriteIcon /> 가 출력된다.

🚨왜 즉시 변경되지 않지?

useEffect(() => {
  const fetchLikeStatus = async () => {
    try {
      const response = await axios.get('/api/postlike/status', {
        params: { userId: userId, postId: postId }
      });
      setIsLiked(response.data); // 백엔드에서 받아온 좋아요 상태를 설정
    } catch (error) {
      console.error('Error fetching like status:', error);
    }
  };

  fetchLikeStatus();
}, [userId, postId]);

useEffect처음 로드될 때 좋아요 상태를 가져오기 때문이다.


🍀상태를 즉시 변경해보자

좋아요 아이콘을 클릭하면, isLiked 상태가 즉시 변경되도록 구현하변 되지 않을까?

const handlePostLike = async () => {
  try {
    const response = await axios.post('/api/postlike', {
      userId: userId,
      postId: postId
    });
    console.log(response.data);
    setIsLiked(true); // 좋아요 상태를 즉시 true로 만든다
  } catch (error) {
    console.error('Error liking the post:', error);
  }
};

<FavoriteBorder /> 아이콘을 클릭하면, 아이콘이 바로 <FavoriteIcon /> 로 바뀐다. 굿👍

하지만, 모달창을 켤 때,
<FavoriteBorder /> 가 보였다가, <FavoriteIcon />로 바뀌는 것을 확인하고 말았다.

🚨초기 UI가 노출된다

async 데이터를 가져오는 시간이 필요하기 때문인 것 같다.
모달창을 띄울 때, useEffect로 좋아요 상태를 호출하기 때문이다.
모달창을 띄울 때, 이미 좋아요 상태를 가지고 있어야할 것 같다.


🍀부모에서 상태를 받아오자

그럼, 부모 컴포넌트에서 isLiked 상태를 가져와야하나? 테스트 해보면 되겠지...

부모 컴포넌트에 좋아요 상태를 가져오는 메서드를 추가했다.

useEffect(() => {
  const fetchLikeStatus = async () => {
    if (loggedInUser && postModal) {
      try {
        const response = await axios.get('/api/postlike/status', {
          params: { userId: loggedInUser.id, postId: postModal.postId }
        });
        setIsLiked(response.data);
      } catch (error) {
        console.error('Error fetching like status:', error);
      }
    }
  };

  fetchLikeStatus();
}, [loggedInUser, postModal]);

<PostActions postId={postModal.postId} userId={loggedInUser.id} isLiked={isLiked} setIsLiked={setIsLiked} />

❗부모 컴포넌트에서 상태를 받아오므로, 자식 컴포넌트에서는 axios 함수를 뺐다.

됐다. 진짜 됐는데, 사진으로만 첨부하니까 잘 모르겠네...
다음에는 영상으로 따오던지 해야겠다.


북마크도 동일한 방식으로 진행하면 될 것 같다.

profile
할 건 해야지

0개의 댓글