본문 바로가기

코딩/ReactJS

리액트, 원하는 게시글의 댓글 목록만 열기(feat. map함수)

반응형

요즘 리액트를 이용해 SNS를 구현하고 있다.

게시글의 댓글 아이콘을 클릭하면 댓글 목록이 렌더링 되도록 하고싶었는데 문제가 발생했다.

바로 한 개의 게시글에서만 댓글 아이콘을 눌러도 다른 게시글의 댓글 목록이 모두 열리는 것.


사실 멋쟁이사자처럼에서 프로젝트를 진행했을 때 해당 기능을 구현해보았었다.

2023.08.31 - [코딩/ReactJS] - react에서 댓글 기능 구현하기(선택된 컴포넌트만 댓글UI 보여주기)

 

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

오늘 하루종일 씨름한 댓글 기능 구현하기 후기... 기존에 댓글 기능을 간단하게 구현해두었지만 서버와의 연동을 위해서 조금 손보고자 시작한게 하루를 뚝딱 집어삼켜버렸다. 처음에는 그냥 a

bebutae.tistory.com

근데 내가 로직을 확실히 이해하지 못했다고 생각했기 때문에 좀 더 깔끔한 코드로 다시 시도해보기로 함.


하나의 게시글에서만 댓글 목록을 렌더링하고 싶은데,

모든 게시글에서 댓글 목록이 렌더링되는 이유를 살펴보면 아래와 같다.

 

function App() {
  const [isComment, setIsComment] = useState(false);
  const datas = [1, 2, 3, 4, 5]
  return (
    datas.map((data, index)=>{
      return (
        {isComment && <Comment/>}
      )
    }
  )
}

위 코드에서는 isComment라는 상태에 따라 <Comment/> 컴포넌트의 렌더링 하도록 했다.

이때 isComment의 값이 true라면 map함수에 의해 5개의 컴포넌트가 렌더링된다.

포스팅 상단에서 언급했던,

'하나의 게시글에서 댓글 아이콘을 누르면 모든 게시글의 댓글 리스트가 렌더링 되는'

문제가 발생하게 되는 것이다.


이 문제를 해결하기 위해서는 map함수로 렌더링되는

5개의 <Comment/> 컴포넌트를 각각 제어할 수 있어야 한다.

function App() {
  const [isComment, setIsComment] = useState(false);
  const [commentIndex, setCommentIndex] = useState();
  
  const datas = [1, 2, 3, 4, 5]
  
  const handleComment = (index) => {
    setCommentIndex(index);
    if (index === commentIndex) {
      setIsComment(false);
      setCommentIndex(9999999999999999999999);
    } else {
      setIsComment(true);
    }
  };  

  return (
    datas.map((data, index)=>{
      return (
        <button
          onClick={()=>{
            handleComment(index)
          }>
          댓글아이콘
        </button>
        {isComment && commentIndex === index && <Comment/>}
      )
    }
  )
}

갑자기 코드가 확 늘어났지만 하나씩 살펴보자면,

        <button
          onClick={()=>{
            handleComment(index)
          }>
          댓글아이콘
        </button>

'댓글아이콘'이라는 버튼을 누르면 handleComment라는 함수가 실행된다.

  const handleComment = (index) => {
    setCommentIndex(index);
    if (index === commentIndex) {
      setIsComment(false);
      setCommentIndex(9999999999999999999999);
    } else {
      setIsComment(true);
    }
  };

handleComment 함수는 map함수로 렌더링한 요소들의 index 값을 인자로 받으며,

인자로 받은 index 값을 commentIndex라는 상태에 할당해준다.

 

만약 인자로 받은 index 값과 commentIndex의 상태값이 동일하다면,

isComment의 상태값을 true로 바꿔준다.

만약 동일하지 않다면 isComment의 값을 false로 바꿔주고,

commentIndex의 값을 999999999999999로 바꿔준다.

 

isComment의 값을 바꿔주는건 <Comment/> 컴포넌트를 렌더링하기 위해서임을 알 수 있지만,

commentIndex의 값은 왜 굳이 999999999999로 바꿔주는걸까?

 

commentIndex의 값이 index와 동일하면 isComment의 값이 false로 바뀐다.

그렇다면 commentIndex의 값을 9999999999로 바꾸지 않는 상태에서 '댓글아이콘'을 3번 누르면 어떻게 될까?

1번 누르면 index와 commentIndex가 같지 않으므로,

isComment의 값이 true로 바뀌면서 <Comment/> 컴포넌트가 렌더링되고,

2번 누르면 index와 commentIndex가 같으므로,

isComment의 값이 false로 바뀌면서 <Comment/> 컴포넌트가 제거된다.

3번 누르면 이미 index와 commentIndex가 같은 상태이므로,

isComment의 값이 false로 유지되며 <Comment/> 컴포넌트가 렌더링되지 않는다.

 

특정 댓글 리스트를 껐다 켜면,

commentIndex의 값을 index와 다르게 만들어주지 않는 한,

다시 해당 댓글 리스트를 켤 수 없다는 뜻.

 

그래서 <Comment/> 컴포넌트를 제거할 때 commentIndex의 값을 9999999999로 바꿔주는 것이다.

이때 999999999999대신 다른 값을 넣어줘도 되는데,

다른 게시글의 index 값과 겹치지 않도록 충분히 큰 값을 넣어줘야 한다.

  const handleComment = (index) => {
    setCommentIndex(index);
    if (index === commentIndex) {
      setIsComment(false);
      setCommentIndex(2);
    } else {
      setIsComment(true);
    }
  };

왜냐면 위 코드와 같이 commentIndex의 값을 2로 바꿔버리는 경우,

index가 2인 게시글의 <Comment/> 컴포넌트가 렌더링되기 때문.


 

솔루션을 적용한 결과물.

내가 원하는 게시글의 댓글만 렌더링 되는 것을 확인할 수 있다.

반응형