React Hook useEffect has a missing dependency 완벽 해결법
1. 도입 – React Hook useEffect has a missing dependency 에러란?
🔗 관련 에러 해결 가이드
React 개발을 하다 보면 ‘React Hook useEffect has a missing dependency’ 경고 메시지를 자주 마주치게 됩니다. 이 경고는 ESLint의 exhaustive-deps 규칙이 useEffect 훅 내부에서 사용되는 변수나 함수가 의존성 배열(dependency array)에 포함되지 않았을 때 발생합니다. 단순한 경고처럼 보이지만, 이를 무시하면 예상치 못한 버그와 stale closure 문제로 이어질 수 있습니다. 특히 상태가 업데이트되지 않거나 오래된 값을 참조하는 문제가 발생할 수 있어 개발자들이 반드시 이해하고 해결해야 하는 중요한 이슈입니다. 이 글에서는 이 에러의 원인과 해결 방법, 그리고 예방 전략까지 완벽하게 알아보겠습니다.
🤖 AI 에러 분석 도우미
이 에러는 다음과 같은 상황에서 주로 발생합니다:
- 코드 문법 오류가 있을 때
- 라이브러리나 의존성 문제
- 환경 설정이 잘못된 경우
- 타입 불일치 문제
💡 위 해결법을 순서대로 시도해보세요. 90% 이상 해결됩니다!
2. 에러 상세 분석
React Hook useEffect has a missing dependency 경고는 React 16.8 버전 이후 Hooks가 도입되면서 함께 등장한 개발 도구입니다. 이 경고의 핵심은 useEffect 내부에서 참조하는 props, state, 또는 함수가 의존성 배열에 명시되지 않았다는 것을 알려줍니다.
예를 들어, 다음과 같은 코드에서 경고가 발생합니다:
function MyComponent({ userId }) {
const [user, setUser] = useState(null);
useEffect(() => {
fetchUser(userId).then(setUser);
}, []); // 경고: userId가 의존성 배열에 없음
return {user?.name};
}
이 경고를 무시하면 userId가 변경되어도 useEffect가 재실행되지 않아 사용자 데이터가 업데이트되지 않는 버그가 발생합니다. React는 함수형 컴포넌트의 순수성을 유지하고 예측 가능한 동작을 보장하기 위해 이러한 검사를 수행합니다. 의존성 배열은 useEffect가 언제 재실행되어야 하는지를 React에게 알려주는 중요한 메커니즘입니다.
3. 발생 원인 5가지
3.1 Props나 State를 의존성 배열에 추가하지 않은 경우
가장 흔한 원인으로, useEffect 내부에서 props나 state를 사용하면서 의존성 배열에 포함시키지 않은 경우입니다.
function Counter({ initialCount }) {
const [count, setCount] = useState(0);
useEffect(() => {
console.log('Current count:', count);
console.log('Initial:', initialCount);
}, []); // 경고: count와 initialCount 누락
}
3.2 컴포넌트 내부에 정의된 함수를 사용하는 경우
useEffect 외부에서 정의된 함수를 내부에서 호출할 때 해당 함수도 의존성으로 간주됩니다.
function SearchComponent() {
const [query, setQuery] = useState('');
const handleSearch = () => {
console.log('Searching for:', query);
};
useEffect(() => {
handleSearch();
}, []); // 경고: handleSearch 누락
}
3.3 객체나 배열 속성에 접근하는 경우
객체의 특정 속성만 사용해도 전체 객체를 의존성에 추가해야 합니다.
function UserProfile({ user }) {
useEffect(() => {
document.title = user.name;
}, []); // 경고: user 또는 user.name 누락
}
3.4 useCallback이나 useMemo로 감싸지 않은 함수
매 렌더링마다 새로 생성되는 함수를 의존성에 추가하면 무한 루프가 발생할 수 있어 개발자들이 의도적으로 제외하는 경우가 있습니다.
3.5 Context 값을 사용하는 경우
useContext로 가져온 값도 의존성 배열에 포함되어야 합니다.
function ThemeComponent() {
const theme = useContext(ThemeContext);
useEffect(() => {
applyTheme(theme);
}, []); // 경고: theme 누락
}
4. 해결방법 7가지
4.1 의존성 배열에 모든 의존성 추가 (권장)
가장 기본적이고 권장되는 방법은 ESLint가 제안하는 대로 모든 의존성을 배열에 추가하는 것입니다.
function MyComponent({ userId }) {
const [user, setUser] = useState(null);
useEffect(() => {
fetchUser(userId).then(setUser);
}, [userId]); // userId 추가
return {user?.name};
}
4.2 useCallback으로 함수 메모이제이션
함수를 의존성으로 사용할 때는 useCallback으로 감싸서 불필요한 재생성을 방지합니다.
function SearchComponent() {
const [query, setQuery] = useState('');
const [results, setResults] = useState([]);
const handleSearch = useCallback(() => {
fetch(`/api/search?q=${query}`)
.then(res => res.json())
.then(setResults);
}, [query]);
useEffect(() => {
handleSearch();
}, [handleSearch]); // 이제 안전하게 의존성 추가 가능
}
4.3 함수형 업데이트 사용
setState의 함수형 업데이트를 사용하면 현재 state를 의존성에서 제거할 수 있습니다.
function Counter() {
const [count, setCount] = useState(0);
useEffect(() => {
const timer = setInterval(() => {
setCount(prev => prev + 1); // count를 의존성에 추가하지 않아도 됨
}, 1000);
return () => clearInterval(timer);
}, []); // 빈 배열 유지 가능
return {count};
}
4.4 useEffect 내부로 함수 이동
함수가 useEffect 내부에서만 사용된다면 내부로 이동시켜 의존성 문제를 해결할 수 있습니다.
function DataFetcher({ id }) {
const [data, setData] = useState(null);
useEffect(() => {
const fetchData = async () => {
const result = await fetch(`/api/data/${id}`);
setData(await result.json());
};
fetchData();
}, [id]); // fetchData는 내부에 있어 의존성에 추가 불필요
}
4.5 객체 구조분해 할당 활용
객체 전체 대신 필요한 속성만 추출하여 의존성을 명확하게 합니다.
function UserProfile({ user }) {
const { name, email } = user;
useEffect(() => {
document.title = name;
console.log('Email:', email);
}, [name, email]); // 명확한 의존성
}
4.6 useRef로 최신 값 참조
의존성으로 추가하고 싶지 않지만 최신 값을 참조해야 할 때 useRef를 사용합니다.
function LogComponent({ value }) {
const valueRef = useRef(value);
useEffect(() => {
valueRef.current = value;
});
useEffect(() => {
const timer = setInterval(() => {
console.log(valueRef.current); // 항상 최신 값 참조
}, 1000);
return () => clearInterval(timer);
}, []); // value를 의존성에 추가하지 않아도 최신 값 사용 가능
}
4.7 ESLint 규칙 비활성화 (최후의 수단)
정말 필요한 경우에만 특정 라인에 대해 규칙을 비활성화합니다.
useEffect(() => {
doSomething();
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []); // 이 방법은 정말 필요할 때만 사용하세요
5. 예방법과 베스트 프랙티스
자동 수정 기능 활용: VSCode 등의 에디터에서 ESLint 자동 수정 기능을 활성화하면 의존성을 자동으로 추가할 수 있습니다. 저장 시 자동 수정되도록 설정하면 편리합니다.
커스텀 Hook 분리: 복잡한 로직은 커스텀 Hook으로 분리하여 의존성 관리를 단순화합니다. 예를 들어 useFetch, useDebounce 같은 재사용 가능한 Hook을 만들어 사용하세요.
의존성 최소화: useEffect 내부에서 정말 필요한 값만 사용하도록 코드를 작성합니다. 불필요한 의존성은 불필요한 재실행을 유발합니다.
정기적인 코드 리뷰: 팀 내에서 useEffect 사용에 대한 가이드라인을 정하고 코드 리뷰 시 의존성 배열을 꼼꼼히 확인하는 습관을 들이세요.
React Strict Mode 사용: 개발 환경에서 Strict Mode를 활성화하면 잠재적인 문제를 조기에 발견할 수 있습니다.
6. 마무리
React Hook useEffect has a missing dependency 경고는 단순한 불편함이 아니라 코드의 정확성을 보장하기 위한 중요한 신호입니다. 이 글에서 소개한 7가지 해결 방법과 예방 전략을 활용하면 안정적이고 예측 가능한 React 애플리케이션을 개발할 수 있습니다. 의존성 배열을 올바르게 관리하는 것은 React Hooks를 마스터하는 첫걸음입니다. 처음에는 번거롭게 느껴질 수 있지만, 이를 통해 버그를 사전에 방지하고 코드 품질을 높일 수 있습니다. 항상 ESLint의 제안을 무시하지 말고, 왜 그런 경고가 발생하는지 이해하려는 노력이 중요합니다.
📚 함께 읽으면 좋은 글
Maximum update depth exceeded 완벽 해결법 – 원인부터 예방까지
📅 2025. 11. 9.
🎯 Maximum update depth exceeded
Maximum update depth exceeded 완벽 해결법 – 원인부터 예방까지
📅 2025. 11. 8.
🎯 Maximum update depth exceeded
Cannot read properties of undefined (reading ‘map’) 완벽 해결법 – 원인부터 예방까지
📅 2025. 11. 6.
🎯 Cannot read properties of undefined (reading ‘map’)
Maximum update depth exceeded 완벽 해결법 – 원인부터 예방까지
📅 2025. 11. 4.
🎯 Maximum update depth exceeded
Warning: Each child in a list should have a unique “key” prop 완벽 해결법 – 원인부터 예방까지
📅 2025. 11. 4.
🎯 Warning: Each child in a list should have a unique “key” prop
💡 위 글들을 통해 더 깊이 있는 정보를 얻어보세요!
📢 이 글이 도움되셨나요? 공유해주세요!
여러분의 공유 한 번이 더 많은 사람들에게 도움이 됩니다 ✨
🔥 공유할 때마다 블로그 성장에 큰 힘이 됩니다! 감사합니다 🙏
💬 여러분의 소중한 의견을 들려주세요!
React Hook useEffect has a missing dependency에 대한 여러분만의 경험이나 노하우가 있으시나요?
⭐ 모든 댓글은 24시간 내에 답변드리며, 여러분의 의견이 다른 독자들에게 큰 도움이 됩니다!
🎯 건설적인 의견과 경험 공유를 환영합니다 ✨
🔔 블로그 구독하고 최신 글을 받아보세요!
🌟 React 에러부터 다양한 실생활 정보까지!
매일 새로운 유용한 콘텐츠를 만나보세요 ✨
📧 RSS 구독 | 🔖 북마크 추가 | 📱 모바일 앱 알림 설정
지금 구독하고 놓치는 정보 없이 업데이트 받아보세요!