React Hook useEffect has a missing dependency 완벽 해결법
도입 – React Hook useEffect has a missing dependency 에러란?
🔗 관련 에러 해결 가이드
React 개발 중 React Hook useEffect has a missing dependency 경고 메시지를 마주한 적이 있으신가요? 이 경고는 React 개발자라면 누구나 한 번쯤 겪는 흔한 문제입니다. useEffect 훅을 사용할 때 의존성 배열(dependency array)에 필요한 값을 누락했을 때 발생하는 이 경고는 단순히 무시하면 예상치 못한 버그로 이어질 수 있습니다. ESLint의 exhaustive-deps 규칙이 이를 감지하여 개발자에게 알려주는데, 이는 컴포넌트의 정확한 동작을 보장하기 위한 중요한 안전장치입니다. 이 글에서는 이 에러의 원인부터 해결 방법, 그리고 예방법까지 완벽하게 정리해드리겠습니다.
🤖 AI 에러 분석 도우미
이 에러는 다음과 같은 상황에서 주로 발생합니다:
- 코드 문법 오류가 있을 때
- 라이브러리나 의존성 문제
- 환경 설정이 잘못된 경우
- 타입 불일치 문제
💡 위 해결법을 순서대로 시도해보세요. 90% 이상 해결됩니다!
에러 상세 분석
이 경고 메시지는 정확히 무엇을 의미할까요? useEffect 내부에서 사용하는 변수나 함수가 의존성 배열에 포함되지 않았을 때 React는 이를 감지합니다. 예를 들어, useEffect 내부에서 props나 state 값을 참조하는데 의존성 배열에 해당 값이 없다면 해당 값이 변경되어도 useEffect가 재실행되지 않습니다. 이는 오래된(stale) 값을 참조하는 클로저 문제를 야기할 수 있습니다. React의 exhaustive-deps ESLint 규칙은 useEffect, useCallback, useMemo 등의 훅에서 사용되는 모든 외부 값을 의존성 배열에 명시하도록 강제합니다. 이 규칙을 따르면 컴포넌트가 항상 최신 값을 사용하고 예측 가능한 동작을 보장할 수 있습니다. 경고를 무시하면 UI가 state와 동기화되지 않거나, 이벤트 핸들러가 오래된 데이터를 사용하는 등의 문제가 발생할 수 있습니다.
발생 원인 5가지
1. props나 state를 의존성 배열에 누락
가장 흔한 원인입니다. useEffect 내부에서 props나 state를 사용하지만 의존성 배열에 포함하지 않은 경우입니다. 예를 들어 userId prop을 사용해 데이터를 fetch하는데 의존성 배열에 userId를 넣지 않으면 userId가 변경되어도 새로운 데이터를 가져오지 못합니다.
2. 함수를 의존성 배열에 누락
컴포넌트 내부에서 정의한 함수를 useEffect에서 호출하지만 의존성 배열에 포함하지 않은 경우입니다. 함수가 props나 state를 참조한다면 해당 함수도 의존성으로 추가해야 합니다. 함수가 렌더링마다 재생성되므로 이를 고려해야 합니다.
3. 객체나 배열을 의존성으로 사용
객체나 배열은 렌더링마다 새로운 참조가 생성됩니다. 따라서 인라인으로 정의된 객체나 배열을 의존성 배열에 넣으면 매 렌더링마다 useEffect가 실행됩니다. 이는 무한 루프를 발생시킬 수 있습니다.
4. useCallback이나 useMemo 없이 함수 전달
부모 컴포넌트에서 자식으로 전달하는 함수가 메모이제이션되지 않으면 매번 새로운 함수 인스턴스가 생성됩니다. 자식 컴포넌트에서 이 함수를 useEffect 의존성으로 사용하면 불필요한 재실행이 발생합니다.
5. 중첩된 속성 접근
user.name과 같이 객체의 중첩된 속성을 useEffect에서 사용할 때, user 전체를 의존성으로 넣으면 user 객체의 다른 속성이 변경되어도 useEffect가 실행됩니다. 필요한 속성만 의존성으로 지정해야 합니다.
해결방법 7가지 (코드 포함)
방법 1: 의존성 배열에 누락된 값 추가
가장 기본적이고 권장되는 방법입니다. 경고 메시지에서 제안하는 대로 누락된 의존성을 추가합니다.
// ❌ 잘못된 예
function Component({ userId }) {
useEffect(() => {
fetchUser(userId);
}, []); // userId가 누락됨
}
// ✅ 올바른 예
function Component({ userId }) {
useEffect(() => {
fetchUser(userId);
}, [userId]); // userId 추가
}
방법 2: useCallback으로 함수 메모이제이션
함수를 의존성으로 사용할 때는 useCallback으로 감싸서 불필요한 재생성을 방지합니다.
// ❌ 문제가 있는 코드
function Component({ id }) {
const fetchData = () => {
api.get(id);
};
useEffect(() => {
fetchData();
}, [fetchData]); // fetchData가 매번 새로 생성됨
}
// ✅ 개선된 코드
function Component({ id }) {
const fetchData = useCallback(() => {
api.get(id);
}, [id]);
useEffect(() => {
fetchData();
}, [fetchData]);
}
방법 3: useEffect 내부로 함수 이동
함수가 useEffect에서만 사용된다면 내부로 이동시켜 의존성 문제를 해결할 수 있습니다.
// ✅ 권장하는 방법
function Component({ userId }) {
useEffect(() => {
const fetchData = async () => {
const data = await api.get(userId);
setData(data);
};
fetchData();
}, [userId]);
}
방법 4: 함수형 업데이트 사용
setState를 사용할 때 이전 state에만 의존한다면 함수형 업데이트를 사용하여 의존성을 제거할 수 있습니다.
// ❌ state를 의존성에 포함
const [count, setCount] = useState(0);
useEffect(() => {
const timer = setInterval(() => {
setCount(count + 1);
}, 1000);
return () => clearInterval(timer);
}, [count]);
// ✅ 함수형 업데이트로 개선
const [count, setCount] = useState(0);
useEffect(() => {
const timer = setInterval(() => {
setCount(prev => prev + 1);
}, 1000);
return () => clearInterval(timer);
}, []);
방법 5: 필요한 속성만 의존성으로 지정
객체 전체가 아닌 실제 사용하는 속성만 의존성 배열에 포함합니다.
// ❌ 객체 전체를 의존성으로
function Component({ user }) {
useEffect(() => {
console.log(user.name);
}, [user]);
}
// ✅ 필요한 속성만 의존성으로
function Component({ user }) {
const userName = user.name;
useEffect(() => {
console.log(userName);
}, [userName]);
}
방법 6: useRef로 최신 값 참조
의존성을 추가하지 않고도 최신 값을 참조해야 할 때 useRef를 활용할 수 있습니다.
function Component({ onEvent }) {
const onEventRef = useRef(onEvent);
useEffect(() => {
onEventRef.current = onEvent;
});
useEffect(() => {
const handler = (e) => onEventRef.current(e);
window.addEventListener('resize', handler);
return () => window.removeEventListener('resize', handler);
}, []); // 빈 의존성 배열
}
방법 7: ESLint 규칙 비활성화 (최후의 수단)
정말 필요한 경우에만 특정 라인에서 규칙을 비활성화할 수 있습니다. 하지만 이는 권장되지 않으며, 주석으로 이유를 명확히 설명해야 합니다.
useEffect(() => {
// 컴포넌트 마운트 시 한 번만 실행되어야 함
initializeApp();
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
예방법과 베스트 프랙티스
1. ESLint 설정 유지: react-hooks/exhaustive-deps 규칙을 활성화 상태로 유지하고 경고를 무시하지 마세요. 이는 버그를 사전에 방지하는 가장 좋은 방법입니다.
2. 의존성 최소화: useEffect 내부에서 사용하는 변수를 최소화하면 의존성 관리가 쉬워집니다. 필요한 로직만 포함하고 나머지는 분리하세요.
3. Custom Hook 활용: 복잡한 useEffect 로직은 커스텀 훅으로 추출하여 재사용성을 높이고 의존성 관리를 단순화하세요.
4. 함수 메모이제이션: useCallback과 useMemo를 적절히 활용하여 불필요한 재렌더링과 useEffect 재실행을 방지하세요.
5. 린터 제안 따르기: ESLint가 제안하는 의존성을 추가하고, 만약 무한 루프가 발생한다면 코드 구조를 재검토하세요. 린터를 억지로 우회하지 마세요.
마무리
React Hook useEffect has a missing dependency 경고는 단순한 성가심이 아니라 코드 품질을 향상시키는 중요한 신호입니다. 이 글에서 소개한 7가지 해결 방법을 상황에 맞게 적용하면 대부분의 경우를 해결할 수 있습니다. 가장 중요한 것은 경고를 무시하지 않고 근본 원인을 이해하여 올바르게 해결하는 것입니다. 의존성 배열을 정확히 관리하면 예측 가능하고 안정적인 React 애플리케이션을 만들 수 있습니다. 오늘 배운 내용을 프로젝트에 바로 적용해보세요!
📚 함께 읽으면 좋은 글
React Hook useEffect has a missing dependency 완벽 해결법 – 원인부터 예방까지
📅 2025. 11. 21.
🎯 React Hook useEffect has a missing dependency
Warning: Each child in a list should have a unique “key” prop 완벽 해결법 – 원인부터 예방까지
📅 2025. 11. 20.
🎯 Warning: Each child in a list should have a unique “key” prop
React Hook useEffect has a missing dependency 완벽 해결법 – 원인부터 예방까지
📅 2025. 11. 20.
🎯 React Hook useEffect has a missing dependency
Cannot read properties of undefined (reading ‘map’) 완벽 해결법 – 원인부터 예방까지
📅 2025. 11. 19.
🎯 Cannot read properties of undefined (reading ‘map’)
Cannot read properties of undefined (reading ‘map’) 완벽 해결법 – 원인부터 예방까지
📅 2025. 11. 18.
🎯 Cannot read properties of undefined (reading ‘map’)
💡 위 글들을 통해 더 깊이 있는 정보를 얻어보세요!
📢 이 글이 도움되셨나요? 공유해주세요!
여러분의 공유 한 번이 더 많은 사람들에게 도움이 됩니다 ✨
🔥 공유할 때마다 블로그 성장에 큰 힘이 됩니다! 감사합니다 🙏
💬 여러분의 소중한 의견을 들려주세요!
React Hook useEffect has a missing dependency에 대한 여러분만의 경험이나 노하우가 있으시나요?
⭐ 모든 댓글은 24시간 내에 답변드리며, 여러분의 의견이 다른 독자들에게 큰 도움이 됩니다!
🎯 건설적인 의견과 경험 공유를 환영합니다 ✨
🔔 블로그 구독하고 최신 글을 받아보세요!
🌟 React 에러부터 다양한 실생활 정보까지!
매일 새로운 유용한 콘텐츠를 만나보세요 ✨
📧 RSS 구독 | 🔖 북마크 추가 | 📱 모바일 앱 알림 설정
지금 구독하고 놓치는 정보 없이 업데이트 받아보세요!