본문 바로가기
Flutter&Dart

Flutter InheritedWidget 동작원리

by 밥바비 2023. 2. 16.
반응형

이전 글을 통해 InheritedWidget이 무엇인지와 함께 사용법에 대해 알아보았다. 이번에는 InheritedWidget의 내부 코드를 살펴보며 실제 플러터 엔진 상에서 InheritedWidget이 어떤 방식으로 동작하는지 알아보려고 한다.

2023.01.17 - [Flutter&Dart] - Flutter InheritedWidget이란, InheritedWidget 사용법

내부 구성

  • InheritedElement(a.k.a ancestor, _inheritedWidgets)
    • createElement를 통해 생성
  • updateShouldNotify 메서드
    • InheritedWidget이 리빌드 될 때 호출된다
    • InheritedWidget을 inherit 한 위젯들이 rebuild 되어야 할지 말아야 할지 결정해 주는 역할을 담당
    • 실제 구현체에서 override 해야 함
    • 여기서 true를 return 하면 Inherit 한 위젯들이 rebuild 됨.
반응형

of 메서드는 어떻게 동작할까?

편의성을 위해 보통 InheritedWidget을 사용하면 of라는 메서드를 구현하여 사용. 형태는 아래와 같다.

static T of(BuildContext context){
	return context.dependOnInheritedWidgetOfExactType<T>();
}

 of 메소드를 호출하면 dependOnInheritedWidgetOfExactType  메서드가 호출된다. 

dependOnInheritedWidgetOfExactType 는 자신을 호출한 context에서 가장 가까운 InheritedWidget<T>을 찾아주는 역할을 한다. 결과적으로 of 메서드를 호출한 위젯의 context와 가장 가까운 InheritedWidget에 접근하여 내부 부모의 데이터를 이용할 수 있게 되는 것.

가장 가까운 InheritedWidget는 어떻게 찾지?

Element Class 내부에 선언된 _inheritedWidgets
Element Class 내부에 선언된 _inheritedWidgets

일반 Element의 경우

위젯 mount 시점에 _updateInheritance 메서드가 실행되고 이를 통해 부모가 가지고 있는 _inheritedWidgets를 자신의 _inheritedWidgets에 할당한다.

updateInheritance 내부 구현 캡쳐
부모의 _inheritedWidgets를 자신의 _inheritedWidgets에 할당

InheritedElement의 경우

InheritedElement의 _updateInheritance는 1번의 경우와 다르게 구현되어 있다. 부모의 _inheritedWidgets가 존재할 경우 이전 값을 모두 유지하면서 자신의 값을 추가한다. 기존에 존재하지 않는 다면 새로 HashMap을 생성한다.

주의해야 하는 것은 runtimeType을 키로 쓰고 있기 때문에 기존에 현재 자신과 같은 타입이 있다면 그 값을 덮어써버린 다는 것. 이 과정을 통해 해당 InheritedWidget의 하위의 위젯은 현재 InheritedWidget을 가장 가까운 InheritedWidget으로 인식하게 된다.

inheritedWidget 내부에 구현된 _updateInheritance 메소드
inheritedWidget 내부에 구현된 _updateInheritance 메소드

 

InheritedWidget 예시 구조
같은 T 타입일 경우 덮어씌운다

즉, Element 마다 자신과 가장 가까운 InheritedWidget을 들고 있기 때문에 가능한 것!

실제 가장 가까운 InheritedWidget에 접근하는 방법

of 메서드에서 dependOnInheritedWidgetOfExactType 가 호출된 후 내부에서 dependOnInheritedElement 가 호출됨

of 메소드 내부 구현
실제 내부 구현 코드

코드를 보면 dependOnInheritedElement를 호출하면서 _inheritedWidgets[T] 값을 ancestor로 넘기는 것을 볼 수 있다.

넘겨진 _inheritedWidgets[T] ancestorupdateDependenciessetDependencies 순으로 메서드가 호출되며 InheritedElement(ancestor) 의 멤버 변수인 _dependents 에 저장됨

InheritedElement 위젯 내부 코드
InheritedElement에 선언된 _dependents

InheritedWidget이 rebuild 될 때, notifyClients 메서드 내부에서 반복문을 돌면서 _dependents에 등록된 위젯들을 리빌드한다.(updateShouldNotify가 true를 리턴할 경우)

notifyClients 구현 화면
notifyClients 내부 구현

이러한 방식을 통해 InheritedWidget의 데이터에 of를 통해 접근한 자식 위젯들이 InheritedWidget 데이터가 변경됐을 때 변경 알림을 받아 리빌드 될 수 있는 것이다.

 

그리고 종종 위젯을 구현하다 보면 didChangeDependencies를 override 하는 경우가 있는데, 그 녀석은 위 과정 중 notifyDependent 내부에 경우 호출 되는 거더라! 그래서 이름이 didChangeDependencies 인 듯하다.

notifyDependent 내부 구현 부분
notifyDependent 내부 구현

 

 

 

 

 

 

반응형

댓글