[React] hook error: Invaild hook call

티라노·2023년 11월 20일
2

훅이 오직 함수형 컴포넌트 안에서만 쓰일 수 있다는 오류 발생.

기존 코드

function Card({ type, data = null }) {
  const handleClick = () => {
    useData("MESSAGES", "DELETE", 318);  // 여기서 문제 발생
  }; //

  const { sender, profileImageURL, relationship, content, font, createdAt } = data;

  return (
    <Container>
			...
      {type === "Edit" && (
        <DeleteIcon>
          <Button type="trash" onClick={handleClick} />
        </DeleteIcon>
      )}
     ...
    </Container>
  );
}
  • Card 컴포넌트 내부에서 사용하고 있으므로, 문제 원인은 handleClick 함수 안에서 useData를 사용하고 있기 때문으로 추측됨. (React의 규칙: 이벤트 핸들러나 비동기 작업에서 훅을 직접 호출하는 것은 허용 X)

수정1

function Card({ type, data = null }) {
  const [state, setState] = useState(true);

  const handleClick = () => {
    setState(!state);
  };
useEffect(() => {
    useData("MESSAGES", "DELETE", 318);
  }, [state]);
  • 따라서 useEffect 안에서 실행해보려고 했으나, 같은 오류 발생…

수정2

function Card({ type, data = null }) {
  const [id, setId] = useState(null);

  const handleClick = () => {
    setId(318); // 누른 버튼의 작성자 id가 리턴된다고 가정
  };

  if (id) useData("MESSAGES", "DELETE", id);
  • useState 사용해서 상태가 변하면 useData함수가 작동하도록 코드 작성

  • 해당 코드가 handleClick에서 setId를 호출하고, 그 후에 useData를 호출하고 있음. 따라서 렌더링 간에 훅의 순서가 변경되어 경고 발생

참고

Error: Invalid hook call. Hooks can only be called inside of the body of a function component 에러 해결방법

[Redux] useDispatch hook 에러 해결기(Error: Invalid hook call)

수정3

  • 직접 이벤트핸들러 안에서 쓰지 않기 위해 useCallback을 쓰면 된다고 하는데…
// 시도 1
function makeServiceHeader() {
  const { name, messageCount, recentMessages, topReactions } = Recipients;

  const [isEmojiVisible, setIsEmojiVisible] = useState(false);
  const [chosenEmoji, setChosenEmoji] = useState(null);

  const createEmoji = useCallback((emoji, type) => {
    CreateEmoji(emoji, type);
  }, []);

  const onEmojiClick = (event, emojiObject) => {
    setChosenEmoji(emojiObject.target.src);
    createEmoji(chosenEmoji, "increase");
  }
// 시도 2
function makeServiceHeader() {
  const createEmoji = CreateEmoji();
  const { name, messageCount, recentMessages, topReactions } = Recipients;
  const [isEmojiVisible, setIsEmojiVisible] = useState(false);
  const [chosenEmoji, setChosenEmoji] = useState(null);

  const onEmojiClick = (event, emojiObject) => {
    setChosenEmoji(emojiObject.target.src);
    useCallback(() => createEmoji(chosenEmoji, "increase"));
  };

  const handleClick = () => {
    setIsEmojiVisible(!isEmojiVisible);
  };

같은 오류 발생.. 최상위에서 선언했고, 핸들러에서 쓴 것 같지도 않은데 왜일까 ㅜㅠ

일단

  1. → 버전 18 넘어서 가능성 없음

  2. → 중복된 리액트 없음

├─┬ emoji-picker-react@4.5.15
│ └── react@18.2.0 deduped
├─┬ react-dom@18.2.0
│ └── react@18.2.0 deduped
├─┬ react-router-dom@6.18.0
│ └── react@18.2.0 deduped
├─┬ react-router@6.18.0
│ └── react@18.2.0 deduped
├── react@18.2.0
├─┬ styled-components@6.1.0
│ └── react@18.2.0 deduped
└─┬ suneditor-react@3.6.1
└── react@18.2.0 deduped

(참고로 오류의 1, 3번 발생 원인도 체크했으나 2번 문제가 확실한 상황이다.)

참고

react Custom Hook을 만들려고 하는데 도움이 필요합니다ㅠㅠ

OKKY - React 버튼 누를 때마다 커스텀 훅이 실행 될 수 있도록은 못하나요???

수정4: 문제 해결

원인은 GET과 달리 POST와 DELETE시 상태를 리턴하기 때문에 그 차이에서 자꾸 오류가 났음.
따라서

📌 GET을 할 때는 uesDate 에 데이터 사용 📌 POST, DELETE일 때는 url만 얼리리턴 받아서 api에 직접 넣어주기

로 useData 코드를 변경하면 문제가 생기지 않는다.

따라서 파일을 (1)url 변경 파일 (2)api 파일 (3)api + 데이터 가공 파일로 다시 나누고

📌 GET: (1) → (3) 📌 POST, DELETE: (1) → (2)

이렇게 아예 hook을 쓰는 메소드를 제한해줬다.

(여러 파일을 수정해야 했기 때문에, 관련 에러 사항에 대해 정리한 사진을 첨부합니다)

profile
어쩌다 프론트 도전기

0개의 댓글