본문 바로가기

Debugging

[ERROR] React Hook useEffect has missing dependencies: ... Either include them or remove the dependency array react-hooks/exhaustive-deps

✅ 에러 로그

React Hook useEffect has missing dependencies: 'date', 'month', 'onGoalMark', and 'year'. Either include them or remove the dependency array  react-hooks/exhaustive-deps

에러가 발생한 곳

useEffect(() => {
    const dateObj = new Date(date)
    const year_ = clickYear(dateObj)
    const month_ = clickMonth(dateObj)
    setYear(year_)
    setMonth(month_)
    onGoalMark({year, month}); // 업데이트된 goalData로 캘린더에 Dot 표시
    }, [goalList]);

 

👉 useEffect 안에서 useEffect의 의존성 배열에 정의되지 않은 변수를 사용하기 때문에 발생하는 것이다.

👉 즉, useEffect 안에서 date와 month, onGoalMark, year을 사용하는데, 의존성 배열에 위의 두 변수가 추가되어있지 않다는 것이다.

👉 따라서 해당 경고를 해결하기 위해서는 useEffect 함수의 의존성 배열에 date와 month, onGoalMark, year을 추가하거나, 해당 변수를 사용하지 않는 방법 중 하나를 선택해야 한다.

✅ 해결 방법

✔️ date month, onGoalMark, year을 useEffect의 의존성 배열에 추가한다.

 useEffect(() => {
    const dateObj = new Date(date)
    const year_ = clickYear(dateObj)
    const month_ = clickMonth(dateObj)
    setYear(year_)
    setMonth(month_)
    onGoalMark({year, month});
    }, [goalList, date, month, onGoalMark, year]);

 

: 또 다른 경고 메시지가 뜨며 useEffect가 계속 실행되어 onGoalMark API가 계속 호출된다. (무한...)

The 'onGoalMark' function makes the dependencies of useEffect Hook (at line 75) change on every render. To fix this, wrap the definition of 'onGoalMark' in its own useCallback() Hook  react-hooks/exhaustive-deps

 

: useEffect 훅의 의존성 배열에 있는 함수들은 해당 함수가 변경될 때마다 새로운 참조로 간주된다. 그러나 함수가 변경되지 않고 그대로인 경우에는 useEffect가 필요 이상으로 다시 실행되는 문제가 발생할 수 있다.

👉 useCallback 훅을 사용하여 함수를 메모이제이션하고, 의존성 배열에서 해당 함수를 사용하도록 설정할 수 있다.

const onGoalMark = useCallback(async (props) => {
    const { year, month } = props;
    try {
        const data = await request(`/calendar/goal/${year}/${month}`, options);
        setColorsByDate(transformMarks(data.result, props));
    } catch (error) {
        alert(error.message);
    }
}, []);

 

: onGoalMark 함수가 useCallback을 통해 메모이제이션되었으므로, useEffect의 의존성 배열에 있는 경우에도 참조가 변경되지 않는다. 따라서, 불필요한 useEffect 실행을 방지할 수 있다.

: 이렇게 수정하고 나면 또 다른 경고 메시지가 뜬다.

The 'options' object makes the dependencies of useCallback Hook (at line 51) change on every render. Move it inside the useCallback callback. Alternatively, wrap the initialization of 'options' in its own useMemo() Hook

 

: options 객체가 useCallback 훅의 의존성 배열에 포함되어 있지만 매 렌더링마다 변경되지 않기 때문에 발생한다.

👉 useMemo 훅을 사용하여 options를 초기화하면 컴포넌트가 렌더링될 때마다 새로운 객체가 생성되는 것을 방지할 수 있다.

const options = useMemo(() => ({
      method: 'GET',
    }), []);

 

✔️ onGoalMark 함수를 useEffect 안으로 옮겨준다. 이렇게 하면 onGoalMark를 의존성 배열에 추가할 필요가 없다.

: 필자의 경우, onGoalMark를 useEffect 밖에서도 사용해야하기 때문에 이 방법을 선택하지 않았다.

✔️ eslint-disable-next-line react-hooks/exhaustive-deps 주석을 추가하면 해당 코드 라인에서만 의존성 배열 경고를 무시할 수 있다..다만, 이 방법은 의존성 배열이 불완전한 상태로 남아있을 수 있으므로 주의해서 사용해야 한다.