기록하는 개발자

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

Web/Redux

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

밍맹030 2022. 3. 7. 22:06
728x90

Error: Invalid hook call

위와같은 에러는 boardList 상태 관리를 위하여 react+typescript환경에 redux 적용 후 문제가 발생하였다.

구글링 결과 관련 해결 방법이 매우 많았지만 useDispatch에서 문제가 발생했던 나의 해결법을 써본다.

 

문제 발생 구간 : GetAlcohol.tsx

GetAlcohol.tsx의 작동 방식


1. 게시판 url인 '/board'로 라우팅되면 서버에 boardlist를 받기위한 get요청을 보낸다.

2. 이때 url에 query parameter로 필터링 정보를 붙여 전달한다.
3. 정상적으로 get이 전송되면 redux의 action을 통해 boardList를 저장한다.

 

상태관리르 위해 redux를 적용하고 useSelector, useDispatch등의 hook을 사용하게 되면서 아래와 같은 오류가 발생하였다.
찾아본 결과 hook 내에서는 함수 호출이 불가능하며 컴포넌트 밖에서는 hook을 선언할 수 없는 등의 제한 사항이 있었다.
그러나 그러한 규칙들에 대한 해당사항이 없기 때문에 더욱 난처한 상황이었다.

 


내가 마주한 오류 메시지

react-dom.development.js:14906 Uncaught Error: Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen for one of the following reasons:

  1. You might have mismatching versions of React and the renderer (such as React DOM)
  2. You might be breaking the Rules of Hooks
  3. You might have more than one copy of React in the same app

console 오류 메시지를 통해 내가 알 수 있는 것은

버튼 클릭 후 실행되는 Getalcohol내의 useDispatch에서 오류가 발생한다는 사실 뿐이었다. 

 

이 때문에 useDispatch부터 invalid hook call, hook 에러 해결 등 며칠 간 구글링하며 무수히 많은 글을 마주했다.

 

그리고 드디어 오늘 오류 메시지가 사라졌다!!

 

useDispatch() 의 호출 과정

   BoardFilter.tsx에 있는 버튼 클릭 → onClick 함수인 GetAlcohol 호출

         GetAlcohol 함수의 최상단에서 useDispatch() 호출

 

위 과정에서 eventhandler가 결과적으로 직접 hook(useDispatch)을 호출하게 되는 점이 문제인 것 같았다.
돌고 돌아 왔지만 redux를 처음 적용하면서 도움을 받았던 블로그에서 useCallback이라는 도움을 받았고 

구글링을 통해 얻은 정보를 조합하여 수정했더니 드디어 오류가 사라졌다.
아래는 수정 전 코드와 수정 후 코드이다.

 

 

수정 전

import React, { useState } from "react";
import "./boardFilter.css";
import axios from "axios";
import useGetAlcoholList from "./useGetAlcoholList";

const createSliderWithTooltip = Slider.createSliderWithTooltip;
const Range = createSliderWithTooltip(Slider.Range);

const BoardFilter = ([생략]) => {
  ...

  return (
    <div>
      ...
      <button onClick={() => GetAlcoholList()}>찾기</button>
    </div>
  );
};
export default BoardFilter;
const GetAlcoholList = ([생략]) => {
    const dispatch = useDispatch();
    axios({
      method: "GET",
      url: '[생략]'
    })
      .then((res) => {
        // 함수 내에서 dispatch를 직접 사용
        dispatch(setBoardList(res.data));
      })
      .catch((err) => {
        console.log("리스트 가져오기 에러", err);
      });
  };
export default GetAlcoholList ;

 

 

수정 후

import React, { useState } from "react";
import "./boardFilter.css";
import axios from "axios";
import useGetAlcoholList from "./useGetAlcoholList";

const createSliderWithTooltip = Slider.createSliderWithTooltip;
const Range = createSliderWithTooltip(Slider.Range);

const BoardFilter = ([생략]) => {
  ...
  
  const { GetAlcoholList } = useGetAlcoholList(filterObj);
  
  return (
    <div>
      ...
      <button onClick={() => GetAlcoholList()}>찾기</button>
    </div>
  );
};
export default BoardFilter;
function useGetAlcoholList([생략]) {
  const dispatch = useDispatch();
  //dispatch를 최상단 함수에서만 사용
 // setBoardList : redux에서 작성한 action 함수
  const setBoard = useCallback(
    (boardItemList: type.boardItem[]) => dispatch(setBoardList(boardItemList)),
    [dispatch]
  );

  const GetAlcoholList = () => {
    axios({
      method: "GET",
      url: '[생략]'
    })
      .then((res) => {
        setBoard(res.data);
      })
      .catch((err) => {
        console.log("리스트 가져오기 에러", err);
      });
  };

  return { GetAlcoholList };
}

useGetAlcoholList를 컴포넌트나 함수가 아닌 custom hook으로 작성하고 custom hook 내부에서 hook을 호출한다.

 → 이 때, useGetAlcoholList는 custom hook이기 때문에 반드시 소문자인 'use'로 시작해야만 한다.

 

setBoard 변수에 useCallback로 action인 setBoardList()를 가져온다.

이렇게 useDispatch를 GetAlcohol 함수 바깥에서 하면 더 이상 오류가 생길리가 없다!!!

 

 

 

구글링 : [ https://medium.com/@umioh1109/%EB%B2%88%EC%97%AD-js-bites-react-hook-is-called-in-a-function-which-is-neither-a-react-function-or-a-custom-33369d62ac84 ]
블로그 : [ https://devlog-h.tistory.com/33 ]

728x90

'Web > Redux' 카테고리의 다른 글

[Redux] React+TypeScript 환경에 Redux 적용하기  (0) 2022.03.07