React Hook useEffect has a missing dependency 완벽 해결법 – 원인부터 예방까지

React Hook useEffect has a missing dependency 완벽 해결법

React 개발 중 React Hook useEffect has a missing dependency 경고 메시지를 마주한 적이 있으신가요? 이 경고는 React의 ESLint 플러그인이 useEffect 훅의 의존성 배열에 누락된 값이 있을 때 발생합니다. 많은 개발자들이 이 경고를 무시하거나 eslint-disable 주석으로 임시 해결하곤 하지만, 이는 예상치 못한 버그와 성능 문제를 야기할 수 있습니다. 이 글에서는 React Hook useEffect has a missing dependency 에러의 근본 원인부터 실전 해결법, 그리고 예방 방법까지 3000자 이상의 상세한 가이드로 완벽하게 설명드리겠습니다.

🤖 AI 에러 분석 도우미

이 에러는 다음과 같은 상황에서 주로 발생합니다:

  • 코드 문법 오류가 있을 때
  • 라이브러리나 의존성 문제
  • 환경 설정이 잘못된 경우
  • 타입 불일치 문제

💡 위 해결법을 순서대로 시도해보세요. 90% 이상 해결됩니다!

에러 상세 분석

이 경고 메시지는 React의 공식 ESLint 플러그인인 eslint-plugin-react-hooksexhaustive-deps 규칙에서 발생합니다. useEffect 내부에서 사용되는 props, state, 또는 컴포넌트 스코프의 변수들이 의존성 배열에 포함되지 않았을 때 나타나는 경고입니다.

React는 useEffect의 의존성 배열에 명시된 값들이 변경될 때만 effect를 재실행합니다. 만약 effect 내부에서 사용하는 값이 의존성 배열에 없다면, 해당 값이 변경되어도 effect가 재실행되지 않아 stale closure 문제가 발생합니다. 이는 오래된 값을 참조하게 되어 예상치 못한 버그를 만들어냅니다.

예를 들어, count라는 state를 useEffect 내부에서 사용하지만 의존성 배열에 포함하지 않으면, effect는 항상 초기 count 값만 참조하게 됩니다. 이런 문제를 사전에 방지하기 위해 React 팀은 이 경고 시스템을 만들었습니다.

발생 원인 5가지

1. State나 Props를 의존성 배열에서 누락

가장 흔한 원인입니다. useEffect 내부에서 state나 props를 사용하면서 의존성 배열에 추가하지 않은 경우입니다.

function Component({ userId }) {
  const [data, setData] = useState(null);
  
  useEffect(() => {
    fetchData(userId); // userId를 사용하지만 의존성 배열에 없음
  }, []); // 경고 발생!
}

2. 함수를 의존성 배열에서 누락

effect 내부에서 호출하는 함수가 컴포넌트 내부에 정의되어 있고, 그 함수가 props나 state를 참조하는 경우입니다.

function Component({ url }) {
  const fetchData = () => {
    fetch(url).then(/* ... */);
  };
  
  useEffect(() => {
    fetchData(); // fetchData가 의존성 배열에 없음
  }, []); // 경고 발생!
}

3. 객체나 배열을 의존성으로 사용

매 렌더링마다 새로운 객체나 배열이 생성되면, 참조가 달라져 무한 루프가 발생할 수 있습니다.

4. useCallback이나 useMemo 없이 인라인 함수 사용

컴포넌트 내부에서 정의된 함수는 렌더링마다 재생성되므로, 의존성 배열에 포함하면 매번 effect가 실행될 수 있습니다.

5. 외부 변수 참조

컴포넌트 외부에 정의된 변수를 effect 내부에서 사용하는 경우, React는 이를 추적할 수 없어 경고가 발생할 수 있습니다.

해결방법 7가지 (코드 포함)

해결법 1: 누락된 의존성을 배열에 추가

가장 기본적이고 권장되는 방법입니다. 경고 메시지가 제안하는 의존성을 모두 추가합니다.

function Component({ userId }) {
  const [data, setData] = useState(null);
  
  useEffect(() => {
    fetchData(userId);
  }, [userId]); // userId 추가
}

해결법 2: useCallback으로 함수 메모이제이션

함수를 useCallback으로 감싸서 불필요한 재생성을 방지합니다.

function Component({ url }) {
  const fetchData = useCallback(() => {
    fetch(url).then(/* ... */);
  }, [url]);
  
  useEffect(() => {
    fetchData();
  }, [fetchData]); // 안전하게 사용 가능
}

해결법 3: 함수를 useEffect 내부로 이동

함수가 effect 내부에서만 사용된다면, 함수를 effect 안으로 옮깁니다.

function Component({ url }) {
  useEffect(() => {
    const fetchData = () => {
      fetch(url).then(/* ... */);
    };
    fetchData();
  }, [url]); // 이제 fetchData는 의존성이 아님
}

해결법 4: setState의 함수형 업데이트 사용

이전 state 값만 필요한 경우, 함수형 업데이트를 사용하면 state를 의존성에서 제거할 수 있습니다.

function Counter() {
  const [count, setCount] = useState(0);
  
  useEffect(() => {
    const timer = setInterval(() => {
      setCount(prev => prev + 1); // count를 의존성에 넣지 않아도 됨
    }, 1000);
    return () => clearInterval(timer);
  }, []); // 빈 배열 유지 가능
}

해결법 5: useRef로 최신 값 참조

effect를 재실행하지 않으면서 최신 값을 참조해야 할 때 useRef를 활용합니다.

function Component({ onUpdate }) {
  const onUpdateRef = useRef(onUpdate);
  
  useEffect(() => {
    onUpdateRef.current = onUpdate;
  });
  
  useEffect(() => {
    const handler = () => onUpdateRef.current();
    // handler는 항상 최신 onUpdate 참조
  }, []); // 의존성 배열 비어있어도 안전
}

해결법 6: useMemo로 객체/배열 메모이제이션

객체나 배열을 의존성으로 사용할 때 useMemo로 안정적인 참조를 유지합니다.

function Component({ user }) {
  const options = useMemo(() => ({
    id: user.id,
    name: user.name
  }), [user.id, user.name]);
  
  useEffect(() => {
    fetchData(options);
  }, [options]); // options가 실제로 변경될 때만 실행
}

해결법 7: ESLint 규칙을 정당한 이유로 비활성화

정말 필요한 경우에만 특정 라인에서 규칙을 비활성화합니다. 주석으로 이유를 명시하는 것이 좋습니다.

useEffect(() => {
  // 컴포넌트 마운트 시 한 번만 실행되어야 함
  initializeApp();
  // eslint-disable-next-line react-hooks/exhaustive-deps
}, []);

예방법과 베스트 프랙티스

첫째, ESLint 설정을 제대로 구성하고 경고를 무시하지 마세요. eslint-plugin-react-hooks를 프로젝트에 설치하고 활성화하면 개발 중 실시간으로 문제를 파악할 수 있습니다.

둘째, effect 내부에서 사용하는 모든 반응형 값(props, state, 파생 값)을 의존성 배열에 포함하는 습관을 들이세요. 이는 React의 데이터 흐름을 명확하게 만들어줍니다.

셋째, 가능한 한 effect를 작게 유지하고, 각 effect가 하나의 관심사만 처리하도록 분리하세요. 복잡한 effect는 의존성 관리가 어려워집니다.

넷째, useCallback, useMemo, useRef 같은 훅들을 적절히 활용하여 불필요한 재실행을 방지하면서도 안전하게 코드를 작성할 수 있습니다.

마지막으로, effect가 정말 필요한지 고민해보세요. 많은 경우 effect 없이 렌더링 중에 계산하거나, 이벤트 핸들러로 처리할 수 있습니다.

마무리

React Hook useEffect has a missing dependency 경고는 React가 여러분의 코드를 더 안전하고 예측 가능하게 만들기 위한 도우미입니다. 이 경고를 무시하거나 억지로 끄기보다는, 근본 원인을 이해하고 적절한 해결 방법을 적용하는 것이 중요합니다. 이 글에서 소개한 7가지 해결법과 베스트 프랙티스를 활용하면, 더 이상 이 경고 메시지로 고민하지 않으실 수 있을 것입니다. 안정적이고 버그 없는 React 애플리케이션 개발에 도움이 되길 바랍니다.

📚 함께 읽으면 좋은 글

1

Error: Element type is invalid 완벽 해결법 – 원인부터 예방까지

📂 React 에러
📅 2025. 10. 20.
🎯 Error: Element type is invalid

2

Cannot read properties of undefined (reading ‘map’) 완벽 해결법 – 원인부터 예방까지

📂 React 에러
📅 2025. 10. 19.
🎯 Cannot read properties of undefined (reading ‘map’)

3

Maximum update depth exceeded 완벽 해결법 – 원인부터 예방까지

📂 React 에러
📅 2025. 10. 18.
🎯 Maximum update depth exceeded

4

React Hook useEffect has a missing dependency 완벽 해결법 – 원인부터 예방까지

📂 React 에러
📅 2025. 10. 17.
🎯 React Hook useEffect has a missing dependency

5

Cannot read properties of undefined (reading ‘map’) 완벽 해결법 – 원인부터 예방까지

📂 React 에러
📅 2025. 10. 16.
🎯 Cannot read properties of undefined (reading ‘map’)

💡 위 글들을 통해 더 깊이 있는 정보를 얻어보세요!

📢 이 글이 도움되셨나요? 공유해주세요!

여러분의 공유 한 번이 더 많은 사람들에게 도움이 됩니다 ✨

🔥 공유할 때마다 블로그 성장에 큰 힘이 됩니다! 감사합니다 🙏

💬 여러분의 소중한 의견을 들려주세요!

이 글에서 가장 도움이 된 부분은 어떤 것인가요?

💡
유용한 정보 공유

궁금한 점 질문

🤝
경험담 나누기

👍
의견 표현하기

⭐ 모든 댓글은 24시간 내에 답변드리며, 여러분의 의견이 다른 독자들에게 큰 도움이 됩니다!
🎯 건설적인 의견과 경험 공유를 환영합니다 ✨

🔔 블로그 구독하고 최신 글을 받아보세요!

📚
다양한 주제
17개 카테고리

정기 업데이트
하루 3회 발행

🎯
실용적 정보
바로 적용 가능

💡
최신 트렌드
2025년 기준

🌟 React 에러부터 다양한 실생활 정보까지!
매일 새로운 유용한 콘텐츠를 만나보세요 ✨

📧 RSS 구독 | 🔖 북마크 추가 | 📱 모바일 앱 알림 설정
지금 구독하고 놓치는 정보 없이 업데이트 받아보세요!

답글 남기기