본문 바로가기

코딩/ReactJS

react에서 댓글 기능 구현하기(선택된 컴포넌트만 댓글UI 보여주기)

반응형

오늘 하루종일 씨름한 댓글 기능 구현하기 후기...

 

기존에 댓글 기능을 간단하게 구현해두었지만

서버와의 연동을 위해서 조금 손보고자 시작한게

하루를 뚝딱 집어삼켜버렸다.

 

처음에는 그냥 axios로 대충 그까이꺼 구현하면 되지 싶었는데

몇가지 난관이 있었다.

 

첫째로, 서버에 delete 요청을 하기 위한 URL에

피드의 ID와 댓글의 ID가 모두 들어갔고

map함수를 중첩해서 피드와 댓글을 구현한 나는

댓글에서 피드의 ID를 불러오는 방법을 찾지 못해 한참을 헤맸다.

 

axios를 이용해 feed 데이터와 comment 데이터를 각각 불러온 뒤

피드 UI를 생성하는 map함수 하위에 댓글 UI를 생성하는 map함수를 넣었다.

{feedData.map(function(a,b)=>{
    return (
        <div>{a.title}</div>
        <div>{commentData.map(function(a,b)=>{
            return (
                <div>{a.comment}</div>
            )})
        }
    )})
}

이러니 댓글단에서 feedId를 불러올 방법이 없었던 것.

 

결국 서버가 반환하는 데이터를 좀 손봤다.

{
    id: 2,
    title: '제목3',
    content: '내용3',
    nickname: 'Nah',
    comments: [
      {
        id: 0,
        nickname: 'kim2',
        comment: '좋아요2',
      },
      {
        id: 1,
        nickname: 'park2',
        comment: '싫어요2',
      },
    ],
},

이런 식으로 피드 데이터의 하위에

다시 배열 형태로 댓글 데이터를 삽입해주었고

댓글 UI는 아예 컴포넌트로 분리하면서

피드에서 불러온 데이터를 props로 전달하도록 수정했다.

 

props로 전달하는 데이터는 2개인데

부모격인 피드의 데이터와

댓글 UI 구현을 위한 댓글 데이터이다.

function Comments(commentData, parentData) {

아까 위에서 서버가 반환하는 데이터를 명시했는데

거기서 comments: [...] 부분이 commentData이고

parentData에는 피드의 id값만 담아주었다.

 

이렇게 전달된 데이터를 이용해

서버에 feedId와 commentId를 무사히 전달할 수 있었다.

  const deleteComment = () => {
    axios
      .delete("http://localhost:8080/comment/" + feedId + "/" + commentId)
      .then((res) => {
        console.log(res);
      })
      .catch((err) => {
        console.log(err.message);
      });
  };

 

두번째로, 나는 첫번째 피드의 댓글만 펼쳤는데

모든 피드의 댓글이 펼쳐지는 문제를 해결해야 했다.

 

기존에 댓글창을 펼치는 코드를 좀 대충 작성해뒀는데

버튼을 누를 때 마다 상태를 true나 false로 변화시켜서

댓글 UI를 보이거나 감추는 로직을 사용했었다.

 

그런데 상태가 피드 컴포넌트 전역에 영향을 미치다보니

이런 방식으로는 모든 피드의 댓글 UI 상태를

일괄적으로 변화시키는 결과를 낳았다.

 

결국 한참을 고민하다가 찾은 방법이

댓글 UI 상태를 true나 false로 관리하는 로직 대신

버튼을 누를 때 마다 feedId를 배열에 저장하거나 제거해서

내가 누른 버튼의 인덱스 값과 배열에 담긴 feedId가 일치할 때만

댓글 UI를 보여주도록 코드를 작성하였다.

 

아래는 댓글 UI를 보여주는 버튼의 코드다.

  <AddCommentIcon
    onClick={() => {
      if (commentIndex.includes(b)) {
        setCommentIndex([
          ...commentIndex.filter((item) => item !== b),
        ]);
      } else {
        setCommentIndex([i.id, ...commentIndex]);
      }
    }}
  />

if문을 이용하여 만약 이미 배열에 해당 피드의 index가 포함되어있다면

배열에서 해당 피드의 인덱스를 제거하고,

그게 아니라면 배열에 해당 피드의 인덱스를 추가하도록 하였다.

 

참고로 commentIndex가 state명이고 includes(b)에서 b가 인덱스를 담고있는 변수명이다.

 

아래 코드는 댓글 UI가 담겨있는 Comments 컴포넌트를 보여줄지 말지 결정하는 코드이다.

commentIndex에 현재 피드의 인덱스 값이 포함되어있는지 체크하여

포함되어 있을 때만 Comments 컴포넌트를 보여준다.

또한 Comments 컴포넌트에 props로 feedId와 comments 데이터를 전달해준다.

{commentIndex.includes(b) ? (
  <>
    <Comments props={i.comments} feed={i.id}></Comments>
  </>
) : null}

이렇게 코드를 작성하니 이제 잘됨

반응형