072DATA

트러블 슈팅 ( React Hooks 규칙 위반 / "Rendered more hooks than during the previous render" ) 본문

Anything/오류 해결(error)

트러블 슈팅 ( React Hooks 규칙 위반 / "Rendered more hooks than during the previous render" )

0720 2024. 10. 16. 23:32

에러 사항

 

"Rendered more hooks than during the previous render" 오류는

React에서 훅을 호출하는 규칙을 위반했을 때 발생한다고 함

 

규칙을 위반했다는 뜻은 조건부로 훅을 호출하거나, 반복문 안에서 훅을 호출할 때를 의미하는데

 

CommentItem 컴포넌트에서 useDeleteComment 훅을 사용하는 방법에 문제가 있었음

 

문제 원인

useCommentNickname 훅을 map 함수 내부에서 호출했기 때문에 에러가 발생했고

React Hooks는 컴포넌트 함수의 최상위 레벨에서만 호출되어야 하며

 

그렇지 않으면 렌더링이 반복될 때 Hooks 호출 순서가 변하게 되어 에러가 발생함

 

문제 코드

 

{data.map((comment) => {
  const { data: memberData, isLoading: isMemberLoading } = useCommentNickname(comment.mem_no);
  if (isMemberLoading) return <li key={comment.comment_id}>로딩중...</li>;
  
  return (
    <li key={comment.comment_id} className="border-b py-2">
      <p className="font-semibold">{memberData ? memberData.mem_nickname : "닉네임 없음"}</p>
      <p>{comment.comment_content}</p>
      <span className="text-gray-500">{comment.comment_date}</span>
    </li>
  );
})}
//코드에서 useCommentNickname 훅이 map 함수 내부에서 호출되고 있어서
//렌더링마다 Hooks 호출 순서가 달라지면서 에러가 발생

 

해결 방법

 

Hooks를 반복문 내에서 호출하지 않도록 컴포넌트를 재구성했으며

map 함수 내에서 훅을 호출하는 대신에 별도의 컴포넌트로 분리하여

최상위 레벨에서 Hooks를 호출할 수 있도록 수정했음

 

수정 코드

const CommentItem = ({ comment }: { comment: CommentTypes }) => {
  const { user } = useUserStore();
  const { data: memberData, isLoading: isMemberLoading } = useCommentNickname(comment.mem_no);
  const findAuth = comment.mem_no === user.userId;
  
  if (isMemberLoading) return <li>로딩중...</li>;

  return (
    <li className="border-b py-2">
      <p className="font-semibold">{memberData ? memberData.mem_nickname : "닉네임 없음"}</p>
      <p>{comment.comment_content}</p>
      <span className="text-gray-500">{comment.comment_date}</span>
      {findAuth && <button className="border-2 p-1">삭제</button>}
    </li>
  );
};

 

const CommentList = ({ id }: Props) => {
  const { data: comments, isLoading, isError } = useCommentData(id);

  if (isLoading) return <>로딩중...</>;
  if (isError) return <>댓글을 불러오는 중 오류가 발생했습니다.</>;

  return (
    <ul>
      {comments && comments.length > 0 ? (
        comments.map((comment) => (
          <CommentItem key={comment.comment_id} comment={comment} />
        ))
      ) : (
        <li>댓글이 없습니다.</li>
      )}
    </ul>
  );
};

 

 

변경 사항

  1. CommentItem 컴포넌트 생성: CommentItem 컴포넌트로 분리하여 각 댓글을 개별적으로 처리하고 최상위 레벨에서 useCommentNickname 훅을 호출하도록 변경
  2. useCommentNickname 위치 수정: map 함수 내부에서 훅이 호출되지 않도록 하여 React Hooks 규칙을 지켜냄

 

 

마치며..

변경 사항을 통해 Hooks 사용 규칙을 준수하고

"Rendered more hooks than during the previous render" 에러를 해결했다..

 

짧은 시간안에 댓글 기능을 구현하다보니 계속 Hooks 사용 규칙을 어기게 되었는데

사실 이런 오류가 있다는 것을 여태껏 모르고 있었기 때문에 오히려 에러에 대한 해결 능력을 키우게 되어서 기쁨!!