🔥 Flutter 핵심 개념 정리: 위젯·엘리먼트·렌더오브젝트 완전 이해하기
Flutter를 공부하다 보면 꼭 이해해야 하는 3가지 개념이 있다.
👉 Widget
👉 Element
👉 RenderObject
처음에는 모두 비슷해 보이지만, Flutter의 UI 렌더링 구조를 정확히 이해하려면 이 세 가지가 어떤 역할을 하는지 명확하게 구분할 필요가 있다.
이 글에서는
위젯 → 엘리먼트 → 렌더오브젝트의 흐름을
가장 쉬운 비유와 실제 예시, 그리고 트리 구조로 이해할 수 있도록 설명한다.
1. Widget — UI의 “설계도”
Widget은 UI가 어떻게 보여야 하는지 정의하는 ‘설계도’이다.
- 불변(immutable)
- 화면의 실제 위치나 크기 정보 없음
- 단순히 “이런 모습으로 만들어줘!” 라는 데이터 덩어리
예를 들어, 아래 코드는 모두 “위젯”이다.
Center()
Padding(padding: ...)
Column()
Text("Hello")
Icon(Icons.star)
하지만 이 위젯들은 실제로 화면에 그려지지 않는다.
설계도이기 때문이다.
2. Element — 위젯의 “실제 위치 정보”
Element는 위젯의 인스턴스이자,
UI 트리에서 ‘현재 위젯이 어디에 존재하는지’를 나타내는 객체이다.
즉,
- 위젯이 어디에 붙어 있는지 (부모/자식 관계)
- 위젯이 가진 상태(State)
- 위젯의 생명주기
등은 모두 Element가 관리한다.
BuildContext의 정체 = Element
위젯의 build() 메서드에서 받는 BuildContext context는
사실 해당 위젯의 Element 자신을 가리키는 참조이다.
예:
@override
Widget build(BuildContext context) {
// context = 이 위젯의 Element
}
그래서 context를 통해
- Theme.of(context)
- Navigator.of(context)
- MediaQuery.of(context)
처럼 조상 위젯이나 환경 정보에 접근할 수 있는 것이다.
모든 위젯은 각각 고유한 Element를 가진다
PostEmptyView, Center, Padding, Column, Text, Icon…
모두 각각의 Element를 갖는다.
3. RenderObject — 실제로 그리는 “엔진 객체”
RenderObject는 Flutter 엔진과 직접 연결되어
실제 화면에 그림을 그리는 역할을 한다.
RenderObject의 역할은 다음과 같다.
- 레이아웃 계산 (size, position)
- 페인팅 (draw)
- Hit Test (터치 이벤트 전달)
- 스크롤, 정렬, 배치 등 물리적 동작
예:
- Text → RenderParagraph
- Column → RenderFlex
- SizedBox → RenderConstrainedBox
RenderObject는 UI를 실제로 구성하는 “진짜 물체(knob, pixel)”이다.
4. 세 가지의 관계를 한 번에 이해하기
정리하면 이렇게 흐른다:
Widget (설계도)
↓ createElement()
Element (위치 + 상태 + 트리 정보)
↓ createRenderObject()
RenderObject (레이아웃 + 그리기)
비유하면?
개념비유역할
| Widget | 집의 설계도 | UI 구조 정의 |
| Element | 실제 방의 위치 | 위젯이 트리에서 어디 있는지 저장 |
| RenderObject | 집의 벽/창문 | 실제 화면에 그려짐 |
5. 트리로 보면 더 명확해진다
아래 예시를 보자.
PostEmptyView
└─ Center
└─ Padding
└─ Column
├─ Icon
├─ SizedBox
├─ Text
├─ SizedBox
└─ Text
이건 위젯 트리다.
Flutter는 이 위젯 트리를 기반으로 동일한 구조의 Element 트리를 생성하고,
그 Element에서 필요한 것들만 RenderObject 트리를 만든다.
6. Rebuild 과정에서는 무엇이 재사용될까?
Flutter가 성능이 빠른 이유는
모든 것을 새로 만드는 것이 아니라 필요한 것만 업데이트하기 때문이다.
구분상태설명
| Widget | 매번 새로 생성됨 | 가벼운 데이터 객체라 부담 없음 |
| Element | 재사용됨 (트리 유지) | 트리 구조와 State 유지 |
| RenderObject | 대부분 재사용됨 | 속성 변경만 업데이트 |
이 구조 덕분에 Flutter는 빠르게 rebuild가 가능하다.
7. BuildContext는 “최상위”가 아니다
많은 초보자들이 오해하는 부분이 있다.
BuildContext는 “해당 위젯의 위치(Element)”를 의미한다.
- PostEmptyView build() 안에서는 PostEmptyView의 context
- Column 내부 Builder에서는 Column 내부의 context
- Text 내부에서는 TextElement의 context
따라서 위젯마다 각자의 BuildContext(Element)가 존재한다.
“최상위 context 하나만 존재하는 구조”가 아니다.
8. 정리: 한 장으로 끝내는 개념 총정리
📘 Widget
- UI 정의 (설계도)
- 불변
- 위치 정보 없음
🧩 Element
- 위젯의 실제 인스턴스
- 트리의 구조 담당 (부모/자식)
- 상태(State) 보관
- BuildContext의 정체
🎥 RenderObject
- 화면에 실제로 그리는 객체
- 레이아웃 / 그리기 엔진
- 필요한 위젯에서만 생성됨
마무리
Flutter의 핵심 구조는
Widget → Element → RenderObject
이 세 가지가 어떻게 협력하느냐를 이해하는 것이다.
이 원리를 제대로 이해하면:
✔ Flutter 렌더링 구조가 명확해지고
✔ BuildContext의 역할이 분명해지고
✔ Rebuild / Layout / Render 단계가 잡히며
✔ 성능 최적화까지 자연스럽게 이해된다.
