과도한 리렌더링 문제 해결하기

숏폼 페이지를 리뉴얼하고 있었는데, 기능이 늘어나면서 버튼이 여기저기 붙기 시작했다.
상단에도 붙고, 오른쪽에도 붙고, 아래도 붙고…
UI는 점점 좋아지는데, 어느 순간 버튼 하나만 눌러도 화면 전체가 버벅대는 현상이 생겼다.
React Profiler 켜서 보니 아주 난리가 나 있었다.
뭐가 문제였냐면…
버튼들이 전부 같은 부모 컴포넌트 안에 있었다.
그러다 보니
- 버튼 클릭 → state 변경
- 부모가 리렌더
- 그 아래 컴포넌트가 싸그리 다 리렌더
라는 구조가 되어버린 거다. 그래서 스크롤만 살짝 해도 버튼들, 리스트, 조합된 UI 전부 다시 그려졌다.
숏폼 같이 화면 내 변동이 많은 구조에서는 체감도 심했다.
그래서 어떻게 접근했냐면
버튼을 기능 단위로 볼 게 아니라 화면에서 변화가 일어나는 단위로 바라봤다.
결론적으로
- HeaderButtons
- RightButtons
- BottomButtons
이렇게 화면 위치 기준으로 쪼갰다.
이러면
- 상단 상태 바뀌면 상단만 리렌더
- 오른쪽 눌리면 오른쪽만 리렌더
가 된다.
그리고 중요한 건, 분리만 하면 끝이 아니라
컴포넌트가 정말 “필요할 때만” 다시 렌더되게 만들어야 했다.
그래서 React.memo 붙이고
버튼 이벤트도 useCallback으로 고정해줬다.
이렇게 설계하면
props가 바뀌지 않으면 직접적으로 다시 렌더하지 않는다.
결과는 꽤 깔끔했다
Profiler 켜서 다시 확인해보니
- 리팩토링 전: 버튼 클릭 시 화면에 빨간 블록이 도배됨 (전부 리렌더)
- 리팩토링 후: 바뀐 위치만 딱 리렌더
“리렌더링이 없다”라고 해도 될 정도로 안정적이었다.
그리고 실제 사용자 체감도 다르다.
- 버튼 눌러도 튕기는 느낌 사라지고
- 스크롤도 부드러워지고
- UI 반응 속도도 빨라짐
숏폼 페이지인데 “동작이 빠르다”
이 느낌이 훨씬 살아났다.
배우게 된 점
이 경험에서 느낀 포인트 몇 가지:
-
컴포넌트 분리는
“역할 기준”이 아니라
“변화가 일어나는 최소 단위 기준” 이 더 실용적일 때가 있다.
-
React Profiler, 진짜 잘 쓰면 답을 명확하게 알려준다.
개발 경험상 “UI 만든다 → 동작한다 → 끝”이 아니라
“이 상태 업데이트는 어디에 영향을 미치는가?”
를 항상 의식하는 게 훨씬 중요하다는 걸 다시 느꼈다.
마무리
정리하자면
- 버튼 많아지고
- state 업데이트 잦고
- 부모가 전부 리렌더되는 구조라면
언젠가는 반드시 성능 문제가 터진다. 이번엔 메모이제이션과 컴포넌트 분리로 깔끔하게 해결했지만
렌더링 비용을 설계한다
이 관점은 계속 가져갈 생각이다. 이게 아마 이번 리뉴얼에서 가장 크게 배운 부분이라고 생각한다.
