
React를 쓰다보면 한번쯤 Maximum update depth exceeded 오류를 볼 수 있다.
최근에 나도 경험했는데.. 이 무한 렌더링 루프를 어떻게 해결했는지, 왜 나타났는지 정리해보려고 한다.
문제 상황
알림 목록 화면이 있었는데 여기에는 복잡한 문제들이 있었다.
1. 여러 탭이 고정되어서 움직이지 않는 문제
2. 탭이 고정되어 있지만 데이터는 다른 탭의 데이터가 나오는 문제
3. 여러 알림 목록에서 더보기 버튼을 누르거나 특정 조건에서 페이지를 진입하면 Maximum update depth exceeded 오류와 함께 앱이 멈추는 현상
4. 목록이 무한 루프를 돌게 되면서 더보기 버튼이 사라져버리는 문제
원인 분석
useNoticeList라는 커스텀 훅 안에는 화면을 렌더링할때마다 매번 새로운 배열과 객체를 만들어내는 부분이 있었다.
// 1. 매번 새로운 '배열'을 생성
const paths = isResident ? ['notify/custom', 'notify'] : ['notify'];
// 2. 매번 새로운 '객체'를 생성
const defaultPageable = {
page: 0,
path: paths[0],
size: 10,
sort: '',
};
React 컴포넌트는 상태가 바뀔 때마다 함수 전체를 다시 실행하며 화면을 새로 그리는데, 이때 저 코드들도 함께 실행되면서
paths와 defaultPageable은 겉은 같지만 메모리 주소는 다른 새로운 값으로 계속 교체되고 있었다.
게다가 useEffect로 paths와 defaultPageable을 dependency array로 삼고 있었기 때문에 이런 상황에서 계속 문제가 발생했다.
1.상태가 바뀌어 화면을 다시 그린다
2. paths와 defaultPageable이 새로운 값으로 교체된다
3. useEffect는 감시 대상이 바꼈다고 판단해 내부 코드를 실행한다
4. useEffect 내부 코드가 또 다시 상태를 바꿔서 1번으로 돌아간다 = 무한 반복
이렇게 되는 문제였다.
해결 방안
무한 루프를 끝나려면 paths와 defaultPageable이 불필요하게 새로 만들어지는걸 막아야했다.
이 값들은 내용물이 바뀌기 전까지는 새로 만들지 말고, 이전에 만들었던 것을 재사용하면 될 것 같았다.
이때 useMemo를 사용해서 해결했다.
useMemo란
useMemo는 memoization이라는 컴퓨터 과학 개념에서 유래한 훅이다.
복잡한 연산의 결과값을 기억(caching) 해두었다가, 필요할 때 다시 계산하지 않고 기억해 둔 값을 그대로 꺼내 쓴다.
React에서 useMemo는 의존성 배열(dependency array)의 값이 바뀌지 않는 한, 이전에 생성했던 값(객체, 배열, 계산 결과 등)을
그대로 재사용하도록 만들어 불필요한 연산과 렌더링을 방지하는 아주 중요한 최적화 도구다.
해결 과정
이 useMemo를 사용해서 무한 루프의 첫번째 문제였던 paths와 그에 의존하던 defaultPageable을 안정화했다.
// 1. paths를 useMemo로 감싸기
// "isResident 값이 바뀔 때만 paths 배열을 새로 계산"
const paths = useMemo(
() => (isResident ? ['notify/custom', 'notify'] : ['notify']),
[isResident],
);
// 2. defaultPageable을 useMemo로 감싸기
// "위에서 만든 paths 배열이 바뀔 때만 객체를 새로 만들기"
const defaultPageable = useMemo(
() => ({
page: 0,
path: paths[0],
size: 10,
sort: '',
}),
[paths],
);
이렇게 하니 paths 배열은 isResident 값이 바뀌지 않는 한 절대 새로 만들어지지 않게 되었다.
paths가 안정화되니까 defaultPageable 객체도 더 이상 불필요하게 새로 만들어지지 않았다.
이렇게 되니 Maximum update depth exceeded 오류도 사라지면서
무한 루프가 사라지니 탭 고정, 데이터 불일치, 더보기 버튼 실종 등 문제들이 같이 사라졌다.
이번 경험을 통해 React의 렌더링 방식과 참조 동등성의 중요성을 한번 더 배웠다..
특히 복잡한 커스텀 훅 안에서는 useCallback과 useMemo의 필요성을 다시 한번 느끼게 됐다.
'Develop > React' 카테고리의 다른 글
| useEffect (0) | 2025.05.25 |
|---|---|
| webX (0) | 2025.05.17 |
| 붕어빵 프로젝트 업데이트 v2.0 (0) | 2025.01.16 |
| 붕어빵 프로젝트 업데이트 v1.1 (0) | 2025.01.09 |
| 붕어빵 프로젝트 업데이트 v1.0 (0) | 2024.12.26 |