BuildContext의 이해

pharmDev·2024년 11월 10일

Flutter 강의 요약:
빌드 컨텍스트 (BuildContext)

이번 강의에서는 **빌드 컨텍스트(BuildContext)**와 **엘리먼트(Element)**에 대한 개념을 다룹니다. 이 개념들은 Flutter의 위젯 트리에서 각각의 위젯이 어디에 위치해 있는지, 어떻게 그려져야 하는지를 이해하는 데 매우 중요합니다.

위젯 - 엘레멘트 - 빌드 컨텍스트 순으로 우리가 접하기 쉬운 대상부터 아래로 파고 들어갑시다.

위젯들의 정의 살펴보기

StatelessWidget 정의

StatelessWidet은 Widget을 상속(extends)합니다.

abstract class StatelessWidget extends Widget {
  const StatelessWidget({ Key? key }) : super(key: key);

  
  StatelessElement createElement() => StatelessElement(this);

  
  Widget build(BuildContext context);
}

StatefulWidget 정의

StatefulWidet 도 Widget을 상속합니다.

abstract class StatefulWidget extends Widget {
  const StatefulWidget({ Key? key }) : super(key: key);

  
  StatefulElement createElement() => StatefulElement(this);

  
  State<StatefulWidget> createState();
}

Widget 클래스의 정의

아래는 Flutter SDK에서 제공하는 Widget 클래스의 기본 정의입니다.

abstract class Widget {
  /// Creates a widget.
  const Widget({ this.key });

  /// A key can be used to uniquely identify this widget among siblings in the same parent.
  final Key? key;

  /// Creates an instance of the corresponding [Element], which manages the widget's
  /// place in the widget tree and handles the lifecycle of the widget.
  ///
  /// Subclasses should override this method to return a new instance of a class
  /// that extends [Element].
  
  Element createElement();

  /// A method that can be used to compare this widget with another one. 
  
  bool operator ==(Object other) {
    return super == other;
  }

  
  int get hashCode => super.hashCode;
}

설명

  • createElement():
    위젯의 트리에서 위치를 관리하고 라이프사이클을 처리하는 Element 객체를 생성합니다. 이 메서드는 위젯 클래스에 따라 StatelessElement 또는 StatefulElement와 같은 적절한 엘리먼트를 생성합니다.

    • 모든 Widget은 자신을 표현하는 엘리먼트를 생성하기 위해 createElement() 메서드를 사용합니다. 이 메서드는 각 위젯의 타입에 맞는 엘리먼트를 생성합니다. 예를 들어:
      • StatelessWidgetStatelessElement를 생성합니다.
        
        StatelessElement createElement() => StatelessElement(this);```
          
        
      • StatefulWidgetStatefulElement를 생성합니다.
        
        StatefulElement createElement() => StatefulElement(this);

    이 메서드를 통해 생성된 엘리먼트는 위젯 트리 내에서 위젯의 위치와 생명 주기를 관리합니다.

  • 이 Widget 클래스는
    Flutter의 모든 위젯이 갖춰야 할 최소한의 공통 기능을 정의하며,
    각 위젯은 이 클래스를 기반으로 자체적인 Element를 생성하고 트리 구조에서 자신의 위치를 관리할 수 있습니다.

그렇다면 Element란 무엇인가?

Element가 지니는 정보

Element는 위젯이 실제 트리 내에서 어떻게 배치되고 그려져야 하는지 관리하는 객체입니다. 위젯은 단순히 화면에 무엇을 보여줄지 정의하는 불변 객체인 반면,
Element는 다음과 같은 정보를 가지고 있습니다:

  • 위젯에 대한 정보: 어떤 위젯인지 (예: Container, Text 등).
  • 부모와 자식 관계: 트리에서 부모가 누구인지, 자식들이 누구인지에 대한 정보.
  • 크기 정보: 위젯이 화면에서 차지하는 크기에 대한 정보.
  • 렌더링 관련 정보: 실제 화면에 어떻게 그려져야 하는지에 대한 정보.

이러한 정보를 통해 엘리먼트는 각 위젯이 화면에 정확히 어떻게 표시되어야 하는지를 관리하고, 위젯 트리의 구조를 유지합니다.

엘리먼트(Element)와 위젯의 관계

엘리먼트는 위젯의 위치, 부모, 자식 정보를 가지고, 렌더링 과정을 관리합니다.
쉽게 말해,

Element의 정의

Element 클래스 정의는 위젯의 위치와 상태를 관리하는 중요한 역할을 합니다. 아래는 Element 클래스의 기본 정의입니다:

abstract class Element extends DiagnosticableTree implements BuildContext {
  Element(this.widget);

  final Widget widget;

  void mount(Element? parent, dynamic newSlot) {
    // 위젯 트리에 Element를 연결하고 초기화하는 작업
  }

  void update(Widget newWidget) {
    // 새로운 위젯으로 갱신하는 작업
  }

  void unmount() {
    // 트리에서 Element를 제거하는 작업
  }

  
  RenderObject? findRenderObject() {
    // 현재 Element와 연결된 RenderObject를 반환
  }

  // 그 외에도 위젯 트리에서 부모, 자식 관계를 관리하고 업데이트하는 다양한 메서드들이 있습니다.
}
  • `implement`는 클래스가 특정 인터페이스나 추상 클래스를 "구현하다"라는 뜻입니다.
    즉, `Element` 클래스가 `BuildContext` 인터페이스를 implements하면, `Element`는 `BuildContext`가 정의한 모든 메서드와 속성을 반드시 구현해야 한다는 의미입니다.

  • Flutter에서 `Element`는 `BuildContext`를 구현하기 때문에 `BuildContext`와 같은 기능을 가질 수 있고, 이를 통해 위젯 트리에서 위젯의 위치와 관련된 작업들을 수행하게 됩니다. 다시 말해, `Element`는 `BuildContext`의 역할을 수행하면서 위젯 트리 내에서 부모, 자식, 형제 위젯 간의 관계를 관리할 수 있습니다.

BuildContext란 무엇인가?

빌드 컨텍스트는 위젯의 위치 정보를 가지고 있는 객체입니다. Flutter의 위젯 트리 구조에서 각 위젯은 서로 연결되어 나무처럼 가지를 뻗어 나가며, 이러한 구조를 통해 Flutter는 화면을 구성합니다.

예를 들어, 최상단에 Column 위젯이 있고, 그 아래에 RowContainer 같은 위젯이 있을 수 있습니다. 빌드 컨텍스트는 각 위젯이 위젯 트리에서 어디에 위치해 있는지를 알 수 있게 합니다. 중요한 것은 위젯 자체는 이 위치 정보를 가지고 있지 않다는 것입니다. 따라서, 빌드 컨텍스트를 통해 위치 정보를 별도로 관리하게 됩니다.

위젯이 위치 정보를 가지고 있으면 특정 위치에서만 사용할 수 있기 때문에, 여러 곳에서 동일한 위젯을 사용할 수 없습니다.
예를 들어, Container 위젯을 여러 번 중첩하여 사용할 수 있는 이유는 Container 자체에 위치 정보가 없기 때문입니다.
이렇게 서로 다른 위치에 여러개의 Containter가 존재할때, 이들을 관리하는 역할을 Element가 수행합니다.

BuildContext의 정의

BuildContext는 Flutter에서 위젯 트리 내에서 특정 위젯의 위치나 그 위젯과 관련된 정보에 접근할 수 있는 중요한 객체입니다.

Flutter SDK에서 BuildContext는 다음과 같이 정의됩니다

abstract class BuildContext {
  Widget get widget;

  RenderObject? findRenderObject();
  
  InheritedWidget? dependOnInheritedWidgetOfExactType<Type extends InheritedWidget>({Object? aspect});

  bool visitAncestorElements(bool Function(Element element) visitor);
  
  // 다른 부모와 관련된 정보에 접근할 수 있는 여러 메서드들이 정의됩니다.
}

빌드 컨텍스트와 엘리먼트의 관계

  • BuildContext는 위젯이 트리에서 어디에 있는지 나타내는 "위치 정보" 역할을 합니다.
  • Element는 실제로 위젯을 화면에 렌더링하거나 업데이트할 수 있는 객체입니다. BuildContext의 기능을 포함해, 위젯의 부모, 자식, 형제 노드를 참조하는 기능을 가집니다.
  • BuildContext는 이 Element를 통해 위젯의 관계를 파악하고 적절한 위치에 올바른 위젯을 배치합니다. 이를 통해 Flutter는 위젯 트리를 효율적으로 렌더링하고 관리할 수 있습니다.

예시

Navigator.of(context)를 사용하여 화면 전환을 할 때,
현재 위젯의 위치를 기반으로 동작하게 됩니다.

void navigateToNextPage(BuildContext context) {
  Navigator.of(context).push(
    MaterialPageRoute(builder: (context) => NextPage()),
  );
}

위 코드에서

  • context는 BuildContext의 기능(위치정보, 부모, 자식 관계를 알려주는 기능)을 부여받은 매개변수 이다. 다른 단어로 바꿔도 무방하다

  • Navigator.of(context)에서 context를 사용해 Navigator는 현재 위젯이 위젯 트리에서 어느 위치에 있는지에 대한 정보를 가져오고,
    그 정보에 기반하여 다음 페이지를 트리에 추가(push)하거나 화면을 전환하는 작업을 합니다.

빌드 컨텍스트의 활용

빌드 컨텍스트는 **미디어 쿼리(MediaQuery)**나 **내비게이터(Navigator)**와 같은 Flutter 기능을 사용할 때 필수적으로 사용됩니다. 이러한 기능들은 위젯 트리에서 위치 정보를 필요로 하기 때문에, 빌드 컨텍스트를 사용하여 필요한 값을 반환합니다.

요약

  • 빌드 컨텍스트는 위젯 트리에서 각 위젯의 위치 정보를 관리하는 객체입니다.
  • 엘리먼트는 위젯의 위치, 부모-자식 관계, 크기 등을 관리하며, 위젯 트리의 구조를 유지합니다.
  • 위젯createElement() 메서드를 통해 자신을 표현하는 엘리먼트를 생성합니다.
  • 빌드 컨텍스트를 사용하여 Flutter의 다양한 기능을 활용할 수 있습니다.
profile
코딩을 배우는 초보

0개의 댓글