-
Flutter는 widget을 그리는 게 아니라 element/render tree를 갱신합니다AI Agent/flutter 2026. 7. 7. 09:00728x90반응형

const 하나에 뚝 떨어진 리빌드 로그 디버그 콘솔에 rebuild 로그를 찍어두고 스크롤을 했더니, 화면에 보이지도 않는 위젯까지 계속 다시 build되고 있었습니다.
리스트를 한 번 튕길 때마다 콘솔이 이렇게 흘렀습니다.[rebuild] HeaderBar [rebuild] FilterChips [rebuild] PriceCard [rebuild] HeaderBar [rebuild] FilterChips [rebuild] PriceCard손가락은 리스트만 건드렸는데, 맨 위에 붙박이로 있는 HeaderBar가 왜 매번 같이 다시 build되는지 이해가 안 됐습니다.
성능이 이상하다는 느낌은 있었는데, 로그로 보니 생각보다 심했습니다.const 한 줄에 로그가 반으로 줄었다
지푸라기 잡는 심정으로, 안 바뀌는 HeaderBar를 const로 감싸 봤습니다.
다시 스크롤했더니 로그가 이렇게 바뀌었습니다.[rebuild] PriceCard [rebuild] PriceCardHeaderBar 줄이 통째로 사라졌습니다.
한 번의 스와이프에 예닐곱 줄씩 흐르던 로그가, 딱 PriceCard 두 줄로 줄어든 겁니다.
처음엔 로그 필터를 잘못 만졌나 싶었습니다.
필터 칩을 껐다 켜고, 콘솔을 맨 위까지 올려 이전 실행 로그와 나란히 놓고 비교했습니다.
그리고 리스트를 다시 몇 번 튕겨봤습니다.
두 번째 실행에서도 HeaderBar는 끝까지 안 찍혔습니다.
FilterChips도 마찬가지고요.
남은 건 실제로 값이 바뀌는 PriceCard뿐이었습니다.
화면은 그동안 멀쩡히 그대로고요.
build를 안 하는데 화면이 그대로라는 게, 그 순간엔 앞뒤가 안 맞았습니다.
저는 그때까지 build 함수가 곧 화면에 픽셀을 얹는 일이라고 막연히 믿고 있었으니까요.// 부모가 몇 번을 rebuild해도 const SizedBox(height: 12); // 이건 다시 안 만들어진다 Padding(padding: EdgeInsets.all(8)); // 이건 매번 새 객체const 위젯은 매번 새로 만들어지지 않고 같은 인스턴스가 재사용됩니다.
부모가 rebuild돼도 const 자식은 "아까 그거랑 똑같지?"에서 통과되고 build가 생략됩니다.
근데 build가 생략됐는데 화면은 왜 멀쩡한가, 그 모순이 저를 트리 쪽으로 끌고 갔습니다.build가 픽셀을 칠하는 게 아니었다
Flutter에는 트리가 세 개 있었습니다.
제가 짜는 widget은 화면 자체가 아니라, 화면을 어떻게 만들지 적어둔 설정값이었습니다.
그걸 받아 실제 화면 객체를 유지하는 element, 크기를 재고 픽셀을 칠하는 render object가 그 뒤에 따로 있었습니다.
build가 하는 일은 widget을 새로 만드는 데서 끝납니다.
새로 만든 widget이 이전 것과 같으면, element는 render object를 건드리지 않고 그대로 둡니다.const가 통한 이유가 이거였습니다.
const 위젯은 이전과 완전히 같다고 못 박혀 있어서, 비교 단계에서 바로 통과되고 build 자체가 생략됩니다.
그러니 로그에 안 찍혀도 화면은 그대로일 수밖에 없었습니다.
로그가 세던 건 build 횟수였지, 화면을 다시 칠한 횟수가 아니었으니까요.rebuild와 repaint는 다른 사건이다
이걸 알고 나니 로그를 읽는 눈이 바뀌었습니다.
build 로그가 많이 찍힌다고 화면을 그만큼 다시 칠하는 게 아니었습니다.
build는 설명서를 다시 쓴 횟수일 뿐이고, 그중 실제로 render object까지 내려가 다시 그려진 건 훨씬 적었습니다.물론 build가 공짜는 아닙니다.
설명서를 매번 새로 쓰고 이전 것과 비교하는 비용은 듭니다.
그래서 안 바뀌는 부분을 const로 막아 아예 비교 대상에서 빼는 게 이득이었습니다.
스와이프 한 번에 헤더까지 build되던 게, 바뀌는 카드 부분만 build되게 정리하고 나니 로그가 절반 아래로 내려갔습니다.
체감 스크롤도 한결 매끄러웠습니다.정확한 수치를 잰 건 아닙니다.
DevTools의 rebuild 카운트가 스와이프 한 번에 세 자리에서 두 자리로 떨어진 정도였습니다.
그래도 손끝에 닿는 반응은 그 숫자보다 크게 느껴졌습니다.
const 하나가 이 정도 차이를 낸다는 게, 그때는 좀 얼떨떨했습니다.지금도 성능이 이상하면 저는 rebuild 로그부터 켭니다.
다만 예전처럼 "build가 많으니 느리다"로 바로 넘어가지 않습니다.
이 build가 설명서만 새로 쓴 건지, render object까지 내려간 건지를 나눠서 봅니다.
그 둘을 같은 걸로 보던 때가, 제일 엉뚱한 데를 붙잡고 있던 시절이었습니다.세 트리를 갈라서 보기 시작하니, const 하나가 왜 그렇게 큰일을 했는지도 그제야 앞뒤가 맞았습니다.
원문 기준
Flutter 아키텍처 개요: https://docs.flutter.dev/resources/architectural-overview (확인일 2026-07-01).
widget/element/render 세 트리 그림이 이 문서에 있는데, 표현이 개정되곤 해서 올리기 전에 그 절만 다시 봅니다.728x90반응형'AI Agent > flutter' 카테고리의 다른 글
골든 테스트 PASS가 실제 화면 증거는 아닙니다 (0) 2026.07.07 같은 상태를 두 곳에서 쓰면 둘 중 하나가 거짓말합니다 (0) 2026.07.07 post-frame, microtask, animation tick은 같은 큐가 아닙니다 (0) 2026.07.06 Riverpod 3에서 await 중 ref가 죽는 순간 (0) 2026.07.06 로컬 상태는 서버 상태의 대체물이 아니라 임시 복사본입니다 (0) 2026.07.06