[React] useCallback으로 useEffect를 효율적으로 관리하기

배성규·2023년 11월 3일

리액트

목록 보기
4/5

개발을 하던 중 React Hook useEffect has a missing dependency: 'fetchMovieData'. Either include it or remove the dependency array.이라는 에러를 마주하게 되었다.
useEffect를 사용하면서 누락된 종속성이 있기 때문에 발생하는 에러인데, 처음 리액트를 쓰다보면 자주 마주칠 수 있는 에러이므로 에러해결을 공유하기위해 글을 작성했다.

1. 먼저 에러 코드 살펴보기

const [nickname, setNickname] = useState<string>("");
const [cookies] = useCookies(["accessToken"]);

useEffect(() => {
  getInfo();
},[]);

const getInfo = async() => {
  try{
    const response = await axios.get(`받아올 API`,{
      headers : {
        Authorization : `Bearer ${cookies.accessToken}`,
      },
    });
    setNickname(response?.이하 코드);
  }catch(error){
  	if(error instanceof AxiosError) {
    	console.log(error);
    }
  }
};
  • accessToken을 포함한 get요청을 받아 데이터에 있는 닉네임 값을 세팅하는 코드이다.
  • 처음 코드를 작성할때 생각했던 부분은 getInfo()를 실행하여 값을 배치하면 되겠다고 했는데 getInfo()에서 useState값을 참조하여 의존성에 영향을 준다는 것을 알았다.

1-2. 해결방법

내가 찾은 해결방법은 아래와 같다.

  1. eslint-disable-next-line react-hooks/exhaustive-deps
  2. useEffect()로 로직을 옮겨서 관리하기
  3. useCallback()을 사용하여 해결하기

1-2-1. eslint-disable-next-line react-hooks/exhaustive-deps

먼저 1번을 사용하는 방법은 문제가 되는 위치에 저 코드를 삽입하는 것이다.

useEffect(() => {
  getInfo();
// eslint-disable-next-line react-hooks/exhaustive-deps
},[]);

그러나 이 방법은 일시적으로 에러를 안보이게 감추는 행위이기 때문에 근본적인 문제를 해결해야한다.

1-2-2. useEffect

useEffect는 구성 요소를 외부 시스템과 동기화할 수 있게 만들어주는 리액트 훅이다.

 const [nickname, setNickname] = useState<string>("");
 const [cookies] = useCookies(["accessToken"]);
 
useEffect(() => {
    const getInfo = async () => {
      await axios
        .get(`${api.user}/info`, {
          headers: {
            Authorization: `Bearer ${cookies.accessToken}`,
          },
        })
        .then((response) => setNickname(response?.data.data.nickname));
    };
    getInfo();
  }, [cookies]);

이 방법을 사용하는 것도 괜찮은 방법이라고 생각한다.
그러나, 다른곳에서 getInfo()함수를 사용할 수 없고 코드가 길어짐에 따라 의존성 배열에 더 많은 값이 들어가 가독성이 떨어지게 된다.

1-2-3. useCallback

useCallback(fn, dependencies)은 재렌더링 사이에 함수 정의를 캐시할 수 있는 리액트 훅이다.

  • fn은 캐시하려는 함수의 값으로, 모든 인수를 가지고 모든 값을 반환할 수 있다.
  • useCallback을 사용하지 않으면 리렌더링마다 함수를 만들고 새롭게 실행되는 데, 사용 시에는 dependencies값이 변화할 때만 함수가 실행되어 불필요하게 함수가 생성되고 실행하는 것을 막을 수 있다.
  • 또한 useEffect내부에 모든 로직을 담는 것이 아니라 로직을 분리하기 때문에 유지보수 관점에서도 useCallback을 사용하는 편이 더 좋다고 느껴진다.
const [nickname, setNickname] = useState<string>("");
const [cookies] = useCookies(["accessToken"]);

const getInfo = useCallback(async () => {
    try {
      const response = await axios.get(`${api.user}/info`, {
        headers: {
          Authorization: `Bearer ${cookies.accessToken}`,
        },
      });
      setNickname(response?.data.data.nickname);
    } catch (error) {
      if (error instanceof AxiosError) {
        console.log(error);
      }
    }
}, [cookies.accessToken]);

useEffect(() => {
    getInfo();
}, [getInfo]);

2. 참고자료

리액트.dev
overreacted.io

profile
FE 유망주🧑‍💻

0개의 댓글