Too many re-renders, setState, 무한 렌더 | 화면이 멈추고 콘솔만 도나?
Too many re-renders는 훅이 고장난 게 아니라 그리는 도중에 setState가 다시 그려짐을 불러 한도를 넘긴 줄입니다. onClick 호출, 렌더 몸통 갱신, Maximum update depth와 구분. React, Next.js, 한국 1인 개발자 기준. 2026년 9월 React useState 문서.
렌더 함수가 끝나기 전에 상태를 바꿔 다시 그리기를 부른 줄입니다. 리액트는 무한 루프를 막으려고 횟수 한도를 두고, 넘으면 Too many re-renders를 던집니다. 이펙트 의존성이 꼬여 나는 Maximum update depth exceeded와 메시지가 다릅니다.
가장 흔한 코드는 조건 없이 렌더 몸통에서 setState를 부르는 경우입니다. if (!ready) setReady(true)처럼 보여도, ready가 다시 false가 되는 계산이면 매 렌더가 상태를 바꿉니다. onClick={setOpen(true)}처럼 핸들러를 넘기는 자리에 호출을 적어 둔 경우도 같습니다. 클릭 전이 아니라 그리는 순간에 실행됩니다.
하이드레이션 미스매치와는 칸이 다릅니다. 서버 HTML과 첫 클라이언트 그림이 다른 줄은 하이드레이션 글입니다. 이쪽은 마운트된 뒤에도 같은 컴포넌트가 자기 상태를 계속 갱신합니다.
메시지 한 줄을 끝까지 | Too many re-renders는 렌더 중 setState, Maximum update depth는 이펙트나 콜백이 상태를 순환 갱신한 줄입니다. 콘솔 첫 문장이 다음 표를 고릅니다.
그리는 도중에 상태를 바꾸면 리액트가 한도를 넘기고 멈춘다
두 줄 에러를 표로 가르기
고치는 파일이 달라집니다. 렌더 몸통인지, 이펙트인지부터 나눕니다.
메시지
언제 나나
먼저 볼 코드
Too many re-renders
렌더 함수 안에서 setState
if 옆 setState, onClick={fn()}
Maximum update depth exceeded
이펙트·콜백이 상태를 순환
useEffect 의존성, 객체 setState
Hydration failed
서버와 첫 그림이 다름
Date, random, window
missing suspense boundary
쿼리 훅에 대체 화면 없음
useSearchParams
쿼리 훅 때문에 빌드가 멈추는 줄은 Suspense 경계 글입니다. 이 글은 런타임에 콘솔이 같은 문장을 반복하는 줄만 봅니다.
렌더 중에 바로 실행되는 호출
function Panel({ startOpen }) {
const [open, setOpen] = useState(false)
// 그릴 때마다 실행됨
if (startOpen) setOpen(true)
// 클릭이 아니라 렌더 때 실행됨
return <button onClick={setOpen(true)}>열기</button>
}
렌더 안의 갱신을 이벤트나 초깃값으로
고치는 원칙은 그리는 함수를 순수하게 두는 것입니다. 초깃값이 필요하면 useState(() => startOpen)처럼 함수 초깃값으로 한 번만 계산합니다. 클릭 뒤에 바꿀 값은 onClick={() => setOpen(true)}처럼 함수를 넘깁니다.
파생 값은 상태로 복제하지 않습니다. const full = first + last면 매 렌더 계산으로 충분합니다. 그걸 setFull으로 저장하려고 렌더나 이펙트에 넣으면 순환이 시작됩니다. 리액트 문서도 이펙트 없이 계산할 수 있으면 상태로 두지 말라고 안내합니다.
부모에서 받은 props를 상태에 복사하는 패턴도 자주 걸립니다. props가 바뀔 때마다 렌더에서 setValue(props.value)를 호출하면 한도를 넘깁니다. 통제 컴포넌트면 상태를 부모만 들고, 복사본이 필요하면 key로 컴포넌트를 다시 마운트하세요.