React Hook useEffect has a missing dependency 완벽 해결법
React 개발을 하다 보면 자주 마주치는 경고 메시지 중 하나가 바로 “React Hook useEffect has a missing dependency”입니다. 이 경고는 React의 ESLint 플러그인인 eslint-plugin-react-hooks가 감지하는 문제로, useEffect 훅의 의존성 배열에 필요한 값이 누락되었을 때 발생합니다. 이 경고를 무시하고 넘어가면 예상치 못한 버그와 오래된 데이터 참조 문제가 발생할 수 있어 반드시 올바르게 처리해야 합니다. 많은 개발자들이 이 경고를 단순히 무시하거나 잘못된 방법으로 해결하려다 더 큰 문제를 만들기도 합니다. 이 글에서는 이 에러의 정확한 원인과 올바른 해결 방법을 상세히 알아보겠습니다.
🤖 AI 에러 분석 도우미
이 에러는 다음과 같은 상황에서 주로 발생합니다:
- 코드 문법 오류가 있을 때
- 라이브러리나 의존성 문제
- 환경 설정이 잘못된 경우
- 타입 불일치 문제
💡 위 해결법을 순서대로 시도해보세요. 90% 이상 해결됩니다!
에러 상세 분석
🔗 관련 에러 해결 가이드
이 경고 메시지는 useEffect 내부에서 사용되는 변수나 함수가 의존성 배열에 포함되지 않았을 때 나타납니다. React는 함수형 컴포넌트가 리렌더링될 때마다 새로운 함수 스코프를 생성하며, useEffect는 의존성 배열의 값이 변경될 때만 다시 실행됩니다. 만약 useEffect 내부에서 사용하는 props, state, 또는 파생된 값들을 의존성 배열에 포함하지 않으면 클로저(closure) 문제로 인해 오래된 값을 참조하게 됩니다.
예를 들어, 컴포넌트의 state가 업데이트되어도 useEffect는 이전 렌더링 시점의 값을 계속 사용하게 되어 UI와 실제 데이터가 불일치하는 문제가 발생합니다. React 팀은 이러한 잠재적 버그를 방지하기 위해 exhaustive-deps 규칙을 도입했으며, 이는 개발자가 실수로 의존성을 누락하는 것을 방지해줍니다. 이 규칙은 단순한 권장사항이 아니라 React의 핵심 원칙인 “명시적 데이터 흐름”을 지키기 위한 필수적인 가이드라인입니다.
발생 원인 5가지
1. Props나 State를 의존성 배열에 누락
가장 흔한 원인으로, useEffect 내부에서 props나 state를 사용하면서 의존성 배열에 포함하지 않는 경우입니다. 컴포넌트가 리렌더링되어 props나 state가 변경되어도 useEffect는 이를 감지하지 못해 오래된 값을 계속 사용합니다.
2. 컴포넌트 내부에 정의된 함수 참조
useEffect 내부에서 컴포넌트 본문에 정의된 함수를 호출할 때, 해당 함수가 의존성 배열에 없으면 경고가 발생합니다. 함수는 매 렌더링마다 새로 생성되므로 함수 내부에서 사용하는 값들도 고려해야 합니다.
3. 객체나 배열의 속성 접근
객체나 배열의 특정 속성만 사용하더라도 전체 객체/배열을 의존성 배열에 포함해야 합니다. user.name만 사용해도 user 객체 전체를 의존성으로 추가해야 합니다.
4. useCallback이나 useMemo로 감싸지 않은 함수/값
매 렌더링마다 새로 생성되는 함수나 계산된 값을 useEffect에서 사용할 때, 메모이제이션 없이 직접 참조하면 무한 루프나 불필요한 재실행이 발생할 수 있습니다.
5. Context나 외부 변수 참조
useContext로 가져온 값이나 컴포넌트 외부에 선언된 변수를 useEffect에서 사용할 때도 의존성 배열에 포함해야 합니다. 특히 Context 값이 변경되어도 useEffect가 재실행되지 않는 문제가 발생할 수 있습니다.
해결방법 7가지 (코드 포함)
방법 1: 의존성 배열에 모든 사용 변수 추가
가장 기본적이고 권장되는 방법입니다. useEffect 내부에서 사용하는 모든 변수를 의존성 배열에 추가합니다.
// 잘못된 코드
function Component({ userId }) {
const [user, setUser] = useState(null);
useEffect(() => {
fetchUser(userId).then(setUser);
}, []); // 경고 발생!
return {user?.name};
}
// 올바른 코드
function Component({ userId }) {
const [user, setUser] = useState(null);
useEffect(() => {
fetchUser(userId).then(setUser);
}, [userId]); // userId를 의존성 배열에 추가
return {user?.name};
}
방법 2: useCallback으로 함수 메모이제이션
컴포넌트 내부 함수를 useEffect에서 사용할 때는 useCallback으로 감싸서 안정적인 참조를 유지합니다.
function Component({ userId }) {
const [data, setData] = useState(null);
const fetchData = useCallback(async () => {
const result = await api.getData(userId);
setData(result);
}, [userId]); // userId가 변경될 때만 함수 재생성
useEffect(() => {
fetchData();
}, [fetchData]); // 안정적인 함수 참조
return {data};
}
방법 3: 함수를 useEffect 내부로 이동
함수가 useEffect에서만 사용된다면 내부로 이동시켜 의존성 문제를 해결할 수 있습니다.
function Component({ userId, apiKey }) {
const [data, setData] = useState(null);
useEffect(() => {
// 함수를 useEffect 내부에 정의
async function fetchData() {
const result = await api.getData(userId, apiKey);
setData(result);
}
fetchData();
}, [userId, apiKey]); // 직접 사용하는 값만 의존성에 추가
return {data};
}
방법 4: 함수형 업데이트 사용
setState에서 이전 state를 참조할 때는 함수형 업데이트를 사용하면 의존성을 줄일 수 있습니다.
function Counter() {
const [count, setCount] = useState(0);
useEffect(() => {
const interval = setInterval(() => {
// count를 의존성에 추가하지 않아도 됨
setCount(prev => prev + 1);
}, 1000);
return () => clearInterval(interval);
}, []); // 빈 배열로 한 번만 실행
return {count};
}
방법 5: useRef로 최신 값 참조
특정 값의 최신 상태를 참조하되 의존성에 포함하고 싶지 않을 때 useRef를 활용합니다.
function Component({ onEvent }) {
const onEventRef = useRef(onEvent);
// 항상 최신 콜백 유지
useEffect(() => {
onEventRef.current = onEvent;
});
useEffect(() => {
function handleEvent(e) {
onEventRef.current(e); // 최신 콜백 호출
}
window.addEventListener('custom', handleEvent);
return () => window.removeEventListener('custom', handleEvent);
}, []); // onEvent를 의존성에 넣지 않아도 됨
}
방법 6: 객체/배열 구조분해 활용
객체나 배열의 일부만 사용한다면 구조분해로 필요한 값만 추출하여 의존성을 명확히 합니다.
function Component({ user }) {
const [greeting, setGreeting] = useState('');
// user 객체 전체 대신 필요한 속성만 추출
const { name, email } = user;
useEffect(() => {
setGreeting(`Hello, ${name} (${email})`);
}, [name, email]); // 명시적으로 사용하는 값만 의존성에 추가
return {greeting};
}
방법 7: eslint-disable 주석 (신중하게 사용)
정말 필요한 경우에만 ESLint 규칙을 비활성화할 수 있지만, 반드시 주석으로 이유를 명시해야 합니다.
function Component() {
const [mounted, setMounted] = useState(false);
useEffect(() => {
// 컴포넌트 마운트 시 한 번만 실행되어야 하는 초기화 로직
setMounted(true);
initializeApp();
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []); // 의도적으로 빈 배열 사용
return App;
}
예방법과 베스트 프랙티스
1. ESLint 규칙 항상 활성화: eslint-plugin-react-hooks를 프로젝트에 설치하고 exhaustive-deps 규칙을 ‘error’로 설정하여 강제합니다.
2. 의존성 배열 자동 수정 활용: VS Code 등의 IDE에서 제공하는 Quick Fix 기능을 사용하면 자동으로 필요한 의존성을 추가할 수 있습니다.
3. 커스텀 훅으로 로직 분리: 복잡한 useEffect 로직은 커스텀 훅으로 분리하면 의존성 관리가 쉬워지고 재사용성도 높아집니다.
4. React DevTools Profiler 사용: 의존성 배열 설정이 올바른지 확인하고, 불필요한 재렌더링이 발생하지 않는지 검증합니다.
5. 의존성 최소화 원칙: useEffect 내부 로직을 단순하게 유지하고, 정말 필요한 의존성만 사용하도록 코드를 구조화합니다. 여러 개의 작은 useEffect로 분리하는 것이 하나의 복잡한 useEffect보다 관리하기 쉽습니다.
마무리
React Hook useEffect has a missing dependency 경고는 React 애플리케이션의 안정성과 예측 가능성을 높이기 위한 중요한 도구입니다. 이 경고를 무시하거나 억지로 우회하려 하지 말고, 근본적인 원인을 이해하고 올바른 방법으로 해결해야 합니다. 의존성 배열을 정확하게 관리하면 버그를 예방하고, 코드의 의도를 명확하게 표현할 수 있으며, 다른 개발자들이 코드를 이해하기 쉬워집니다. 이 글에서 소개한 7가지 해결 방법을 상황에 맞게 적용하면 대부분의 의존성 문제를 해결할 수 있을 것입니다. React의 규칙을 따르는 것이 처음에는 번거로워 보일 수 있지만, 장기적으로는 유지보수하기 쉽고 안정적인 애플리케이션을 만드는 지름길입니다.
📚 함께 읽으면 좋은 글
Cannot update a component while rendering 완벽 해결법 – 원인부터 예방까지
📅 2025. 10. 23.
🎯 Cannot update a component while rendering
Cannot update a component while rendering 완벽 해결법 – 원인부터 예방까지
📅 2025. 10. 23.
🎯 Cannot update a component while rendering
Error: Element type is invalid 완벽 해결법 – 원인부터 예방까지
📅 2025. 10. 23.
🎯 Error: Element type is invalid
Cannot update a component while rendering 완벽 해결법 – 원인부터 예방까지
📅 2025. 10. 22.
🎯 Cannot update a component while rendering
Maximum update depth exceeded 완벽 해결법 – 원인부터 예방까지
📅 2025. 10. 22.
🎯 Maximum update depth exceeded
💡 위 글들을 통해 더 깊이 있는 정보를 얻어보세요!
📢 이 글이 도움되셨나요? 공유해주세요!
여러분의 공유 한 번이 더 많은 사람들에게 도움이 됩니다 ✨
🔥 공유할 때마다 블로그 성장에 큰 힘이 됩니다! 감사합니다 🙏
💬 여러분의 소중한 의견을 들려주세요!
이 글에서 가장 도움이 된 부분은 어떤 것인가요?
⭐ 모든 댓글은 24시간 내에 답변드리며, 여러분의 의견이 다른 독자들에게 큰 도움이 됩니다!
🎯 건설적인 의견과 경험 공유를 환영합니다 ✨
🔔 블로그 구독하고 최신 글을 받아보세요!
🌟 React 에러부터 다양한 실생활 정보까지!
매일 새로운 유용한 콘텐츠를 만나보세요 ✨
📧 RSS 구독 | 🔖 북마크 추가 | 📱 모바일 앱 알림 설정
지금 구독하고 놓치는 정보 없이 업데이트 받아보세요!