Maximum update depth exceeded 에러란?
🔗 관련 에러 해결 가이드
React 개발을 하다 보면 콘솔창에 빨간 에러 메시지가 나타나며 애플리케이션이 멈춰버리는 경험을 하게 됩니다. 그 중에서도 ‘Maximum update depth exceeded’ 에러는 초보 개발자부터 숙련된 개발자까지 자주 마주치는 까다로운 문제입니다. 이 에러는 React 컴포넌트가 무한 루프에 빠져 계속해서 리렌더링을 시도할 때 발생하는데, 브라우저가 과부하로 다운되는 것을 막기 위해 React가 강제로 중단시키는 보호 메커니즘입니다. 이 글에서는 이 에러의 근본 원인부터 실전 해결법, 그리고 예방 방법까지 체계적으로 알아보겠습니다.
🤖 AI 에러 분석 도우미
이 에러는 다음과 같은 상황에서 주로 발생합니다:
- 코드 문법 오류가 있을 때
- 라이브러리나 의존성 문제
- 환경 설정이 잘못된 경우
- 타입 불일치 문제
💡 위 해결법을 순서대로 시도해보세요. 90% 이상 해결됩니다!
에러 상세 분석
Maximum update depth exceeded 에러의 정확한 메시지는 다음과 같습니다: “Maximum update depth exceeded. This can happen when a component repeatedly calls setState inside componentWillUpdate or componentDidUpdate. React limits the number of nested updates to prevent infinite loops.” 이 에러는 React가 내부적으로 설정한 업데이트 깊이 제한(보통 50회)을 초과했을 때 발생합니다. React는 컴포넌트의 상태(state)가 변경될 때마다 리렌더링을 수행하는데, 만약 렌더링 과정에서 또다시 상태 변경이 일어나면 연쇄적인 렌더링이 발생합니다. 이런 상황이 무한히 반복되면 브라우저 메모리가 고갈되고 성능이 급격히 저하됩니다. React는 이를 감지하여 일정 횟수 이상의 업데이트가 발생하면 에러를 던지고 렌더링을 중단시킵니다. 이는 개발자에게 코드에 논리적 오류가 있음을 알려주는 중요한 신호입니다.
발생 원인 5가지
1. 이벤트 핸들러에서 함수를 즉시 실행
가장 흔한 원인은 onClick이나 onChange 같은 이벤트 핸들러에 함수를 참조가 아닌 즉시 실행 형태로 전달하는 것입니다. onClick={handleClick()}처럼 괄호를 붙이면 렌더링 시점에 함수가 즉시 실행되고, 그 함수가 상태를 변경하면 다시 렌더링이 일어나 무한 루프가 발생합니다.
2. useEffect 의존성 배열 문제
useEffect 훅에서 상태를 변경하는데, 그 상태가 의존성 배열에 포함되어 있으면 무한 루프가 발생합니다. useEffect 내부에서 setState를 호출하면 리렌더링이 일어나고, 이는 다시 useEffect를 트리거하여 끝없이 반복됩니다.
3. 렌더링 중 직접 setState 호출
컴포넌트 함수 본문에서 직접 setState를 호출하는 경우입니다. 렌더링이 일어날 때마다 setState가 실행되고, 이는 다시 렌더링을 트리거하여 순환 구조가 만들어집니다.
4. 부모-자식 간 무한 상태 전파
부모 컴포넌트가 자식에게 props를 전달하고, 자식이 그 props를 바탕으로 부모의 상태를 변경하는 콜백을 호출하면, 부모가 다시 렌더링되고 자식도 리렌더링되며 무한 루프가 발생할 수 있습니다.
5. 객체나 배열을 의존성으로 사용
useEffect나 useMemo의 의존성 배열에 객체나 배열을 직접 넣으면, 매 렌더링마다 새로운 참조가 생성되어 의존성이 변경된 것으로 간주됩니다. 이로 인해 effect가 계속 실행되어 무한 루프에 빠질 수 있습니다.
해결방법 7가지
방법 1: 이벤트 핸들러 올바르게 전달하기
함수를 참조로 전달하거나 화살표 함수로 감싸서 전달합니다.
// 잘못된 예
// 올바른 예 1: 함수 참조 전달
// 올바른 예 2: 별도 핸들러 함수
const handleClick = () => {
setCount(count + 1);
};
방법 2: useEffect 의존성 배열 수정
상태를 의존성에서 제거하거나 함수형 업데이트를 사용합니다.
// 잘못된 예
useEffect(() => {
setCount(count + 1);
}, [count]);
// 올바른 예: 의존성 제거 또는 조건 추가
useEffect(() => {
if (someCondition) {
setCount(prev => prev + 1);
}
}, [someCondition]);
방법 3: 렌더링 로직과 상태 업데이트 분리
컴포넌트 본문에서 직접 setState를 호출하지 않습니다.
// 잘못된 예
function Component() {
const [count, setCount] = useState(0);
setCount(count + 1); // 렌더링 중 호출
return {count};
}
// 올바른 예: useEffect나 이벤트 핸들러에서 호출
function Component() {
const [count, setCount] = useState(0);
useEffect(() => {
setCount(1);
}, []);
return {count};
}
방법 4: 조건부 상태 업데이트
상태를 업데이트하기 전에 조건을 확인합니다.
useEffect(() => {
if (data && !isLoaded) {
setIsLoaded(true);
}
}, [data, isLoaded]);
방법 5: useCallback으로 함수 메모이제이션
콜백 함수를 메모이제이션하여 불필요한 리렌더링을 방지합니다.
const handleUpdate = useCallback(() => {
setData(newData);
}, [newData]);
useEffect(() => {
handleUpdate();
}, [handleUpdate]);
방법 6: 객체/배열 의존성 최적화
객체나 배열 대신 원시 값을 의존성으로 사용하거나 useMemo를 활용합니다.
// 잘못된 예
useEffect(() => {
fetchData(config);
}, [config]); // config는 매번 새로운 객체
// 올바른 예
const configString = JSON.stringify(config);
useEffect(() => {
fetchData(config);
}, [configString]);
방법 7: 상태 업데이트 로직 검토
복잡한 상태 관리는 useReducer로 전환하여 예측 가능하게 만듭니다.
const reducer = (state, action) => {
switch(action.type) {
case 'INCREMENT':
return { count: state.count + 1 };
default:
return state;
}
};
const [state, dispatch] = useReducer(reducer, { count: 0 });
예방법과 베스트 프랙티스
Maximum update depth exceeded 에러를 예방하려면 몇 가지 원칙을 따라야 합니다. 첫째, 이벤트 핸들러는 항상 함수 참조로 전달하고 렌더링 시점에 실행되지 않도록 합니다. 둘째, useEffect의 의존성 배열을 신중하게 관리하고, 필요하다면 eslint-plugin-react-hooks를 활용해 경고를 확인합니다. 셋째, 컴포넌트 본문에서는 순수 함수 원칙을 지키고 부수 효과를 useEffect나 이벤트 핸들러로 격리합니다. 넷째, React DevTools의 Profiler를 사용해 불필요한 리렌더링을 모니터링합니다. 다섯째, 복잡한 상태 로직은 커스텀 훅으로 분리하여 재사용성과 테스트 가능성을 높입니다. 이러한 습관을 들이면 대부분의 무한 루프 문제를 사전에 방지할 수 있습니다.
마무리
Maximum update depth exceeded 에러는 처음에는 당황스럽지만, 원인을 이해하고 나면 충분히 해결 가능한 문제입니다. 핵심은 React의 렌더링 사이클을 이해하고, 상태 업데이트가 언제 어떻게 일어나는지 명확히 파악하는 것입니다. 이 글에서 소개한 7가지 해결 방법을 참고하여 여러분의 프로젝트에 적용해보세요. 에러가 발생했을 때는 콘솔의 스택 트레이스를 꼼꼼히 확인하고, 어떤 컴포넌트에서 무한 루프가 시작되는지 추적하는 것이 중요합니다. 지속적인 코드 리뷰와 테스트를 통해 안정적인 React 애플리케이션을 만들어가시기 바랍니다.
📚 함께 읽으면 좋은 글
Maximum update depth exceeded 완벽 해결법 – 원인부터 예방까지
📅 2025. 11. 3.
🎯 Maximum update depth exceeded
Maximum update depth exceeded 완벽 해결법 – 원인부터 예방까지
📅 2025. 10. 22.
🎯 Maximum update depth exceeded
Maximum update depth exceeded 완벽 해결법 – 원인부터 예방까지
📅 2025. 10. 18.
🎯 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
Cannot update a component while rendering 완벽 해결법 – 원인부터 예방까지
📅 2025. 11. 3.
🎯 Cannot update a component while rendering
💡 위 글들을 통해 더 깊이 있는 정보를 얻어보세요!
📢 이 글이 도움되셨나요? 공유해주세요!
여러분의 공유 한 번이 더 많은 사람들에게 도움이 됩니다 ✨
🔥 공유할 때마다 블로그 성장에 큰 힘이 됩니다! 감사합니다 🙏
💬 여러분의 소중한 의견을 들려주세요!
이 글에서 가장 도움이 된 부분은 어떤 것인가요?
⭐ 모든 댓글은 24시간 내에 답변드리며, 여러분의 의견이 다른 독자들에게 큰 도움이 됩니다!
🎯 건설적인 의견과 경험 공유를 환영합니다 ✨
🔔 블로그 구독하고 최신 글을 받아보세요!
🌟 React 에러부터 다양한 실생활 정보까지!
매일 새로운 유용한 콘텐츠를 만나보세요 ✨
📧 RSS 구독 | 🔖 북마크 추가 | 📱 모바일 앱 알림 설정
지금 구독하고 놓치는 정보 없이 업데이트 받아보세요!