[Flutter] Widget, Element, RenderObject 트리

Sooooooah·2023년 5월 2일
0

플러터

목록 보기
4/7

플러터를 구성하는 3가지 트리에 대해 알아보았다.

Widget tree

위젯트리는 불변(immutable) 오브젝트로 구성되어 있다.
자주 바꿀 수 있는 위젯 트리의 업데이트에 순간적으로 대응할 수 있게 설계되어 있다.

context

각 위젯은 context를 갖고 있다. context는 위젯에 대한 meta 정보나, 위젯트리에서의 위치를 나타내준다. 엘리먼트 트리는 이 위젯에 대한 context로 구성되어 있다.

위젯 트리에서의 위치정보를 갖고 있기 때문에 이것을 통해서 위젯들간의 위치를 정확히 파악할 수 있다. inherent widget에서는 context의 위치 정보를 사용하여 다른 위젯들과 곧장 연결한다. (ex:MediaQuery나 Theme같은 것들)

BuildContext

BuildContext는 현재 빌드에 대한 정보를 저장하는 객체이다. 지원되는 최소 및 최대 플러터 버전, 기기 화면 크기 및 픽셀 밀도, 현재 활성화된 테마 등의 정보를 제공한다.

모든 위젯은 자신만의 buildContext를 갖고 있고, StatelessWidget.build or State.build에 의해 반환되는 위젯의 부모가 된다.

class MyPage extends StatelessWidget {
	
    Widget build(BuildContext context) {
    	return Scaffold(
        	// ...
        )
    }
}

build 메서드를 통해서 Scaffold 위젯이 부모인 MyPage의 BuildContext를 물려받아 리턴해준다.

Builder Class

지금까지 사용했던 context는 무시하고 새로운 context로 새로운 위젯을 만든다.

Element tree

가변(mutable) 오브젝트로 구성되어 있다.
위젯 트리의 상태를 관리, 렌더오브젝트 트리의 라이프사이클을 관리한다.

불변인 위젯트리를 대신해서 상태를 관리해주고 위젯 트리와 렌더오브젝트 트리의 중재 역할이다.

RenderObject tree

화면 렌더링과 그리기를 담당한다. 가변 객체로 구성되어 있다.
플러터가 실제로 화면에 표시할 때 참조하는 것은 위젯 트리가 아닌 렌더오브젝트 트리가 된다.

위젯 트리와 엘리먼트 트리

서로 일대일에 해당하는 요소를 갖고 있다. 위젯은 불변이고 빠르고 생성, 파기된다.
그러나 StatefulWidget에서 setState를 사용하면 값이 다시 작성되는데 엘리먼트 트리가 StateObject라는 상태를 만들고 관리하기 때문에 가능한 일이다.

setState에서 값이 변경되면 stateObject가 dirty되어 변경의 필요가 있는 것을 인식. StateObject가 최신화되고 엘리먼트에 대응하는 위젯이 빌드되어 재작성된다. 이때 엘리먼트 트리는 재작성 비용이 높기때문에 최대한 재사용을 하게 된다.

엘리먼트 트리와 렌더오브젝트 트리는 위젯 트리가 변경되어도 성능을 위해 필요한 만큼 재사용된다.

profile
즐거운 서비스를 추구합니다.

1개의 댓글

comment-user-thumbnail
2023년 5월 15일

본문 글로는 context와 BuildContext를 구분하셨는데 통상 BuildContext 하나로 이해하는게 어떨까요?
그리고 build 메서드는 Widget을 리턴하며, Builder 위젯의 builder 속성에 전달되는 콜백의 BuildContext는 새로운 context가 아니라 바로위 Builder위젯의 context입니다.(hashcode를 찍어보면 알 수 있습니다.) 문맥상 Builder위젯의 콜백이 독립적인 Widget 트리를 만드는것으로 이해하신것 같아 설명드렸습니다. Scaffold context가 Builer ctx2 --> container context 로 연결하려면 Scaffold context를 무시하면 안되겠^^

final gKey = GlobalKey();
...
Widget build(BuildContext context) {
return Scaffold(
body: Builder(
key: gKey,
builder: (BuildContext ctx2) {
print(gKey.currentContext.hashCode);
print(ctx2.hashCode);
return Container();
},
),
);
}

답글 달기