Flutter Framework 내부의 위젯 종류에는 크게 3가지 정도가 있다.
StatefulWidget, StatelessWidget, InheritedWidget
StatefulWidget과 statelessWidget은 지난 글에서 내용을 확인 할 수 있고, 그 다음 InheritedWidget에 대하여 알아보고자 한다.
InheritedWidget
- InheritedWidget은 정보를 트리 아래로 효율적으로 전달하기 위한 위젯의 기본 클래스다.
class FrogColor extends InheritedWidget {
const FrogColor({
super.key,
required this.color,
required super.child,
});
final Color color;
static FrogColor? maybeOf(BuildContext context) {
return context.dependOnInheritedWidgetOfExactType<FrogColor>();
}
static FrogColor of(BuildContext context) {
final FrogColor? result = maybeOf(context);
assert(result != null, 'No FrogColor found in context');
return result!;
}
@override
bool updateShouldNotify(FrogColor oldWidget) => color != oldWidget.color;
}
class MyPage extends StatelessWidget {
const MyPage({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
body: FrogColor(
color: Colors.green,
child: Builder(
builder: (BuildContext innerContext) {
return Text(
'Hello Frog',
style: TextStyle(color: FrogColor.of(innerContext).color),
);
},
),
),
);
}
}
BuildContext.dependOnInheritedWidgetOfExactType<T>
해당 메서드는 트리에서 가장 가까운 T 타입의 위젯을 리턴하여 준다.
bool updateShouldNotify(FrogColor oldWidget) => color != oldWidget.color;
해당 메서드는 상태변화가 적용되어야 하는지에 대한 boolean 값을 리턴하도록 구현하여야 한다.
Flutter framework 내부의 InheritedWidget에 대한 주석을 살펴 보면, 코드상에서 볼 수 있듯이 ‘maybeOf’ method는 InheritedWidget을 상속받은 nullable T를 리턴하도록 하고, ‘of’ method는 null이 리턴될 때 오류를 발생시킨다고 되어있다.
또한 주석 상의 용례를 보면 builder를 사용하여 BuildContext를 parameter로 받아 ‘of’ method를 사용하여 FrogColor를 찾아내어 ‘Hello Frog’ String의 스타일에 적용한다.
class MyPage extends StatelessWidget {
const MyPage({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
body: FrogColor(
color: Colors.green,
child: Text(
'Hello Frog',
style: TextStyle(color: FrogColor.of(context).color),
);
),
);
}
}
다음과 같은 예시를 확인 해 보자. 해당 코드가 실행 될 경우, FrogColor.of(… method에서 오류가 발생한다. 해당 ‘of’ method에 주어진 context는 FrogColor를 찾을 수 없기 때문이다.
BuildContext와 Widget Tree 에 관한 내용은 다음에 추가적으로 확인 해 보도록 하자.
InheritedWidget 사용시 rebuild 에 비용이 많이 소모가 될 경우 InheritedModel을 사용 할 수 있다. InheritedModel의 주석을 확인 해 보면,
InheritedWidget의 종속 위젯들은, InheritedWidget.updateShouldNotify를 통하여 InheritedWidget이 바뀔 때 무조건 rebuild된다. InheritedModel은 무조건 rebuild되는 것을 제외하면 InheritedWidget과 유사하다. 라고 되어있다.
class ABModel extends InheritedModel<String> {
const ABModel({
super.key,
this.colorA,
this.colorB,
required super.child,
});
final Color? colorA;
final Color? colorB;
@override
bool updateShouldNotify(ABModel oldWidget) {
return colorA != oldWidget.colorA || colorB != oldWidget.colorB;
}
@override
bool updateShouldNotifyDependent(ABModel oldWidget, Set<String> dependencies) {
return (colorA != oldWidget.colorA && dependencies.contains('colorA'))
|| (colorB != oldWidget.colorB && dependencies.contains('colorB'));
}
// ...
}
class MyPage extends StatelessWidget {
const MyPage({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
body: ABModel(
colorA: Colors.green,
colorB: Colors.blue,
child: Builder(
builder: (BuildContext innerContext) {
final model = InheritedModel.inheritFrom<ABModel>(
innerContext,
aspect: 'colorA',
);
return Text(
'Hello Frog',
style: TextStyle(color: model.colorA),
);
},
),
),
);
}
}
InheritedModel.inheritFrom<T> method를 사용하여 InheritedModel를 찾을 수 있다.
만약 aspect 인자가 null 이라면 연관된 모든 항목에 대하여 업데이트를 시키게 된다.
이와같이 InheritedWidget, InheritedModel을 간단하게 예시를 통하여 알아보았다.
여러가지 상황에서 유용하게 쓸 수 있을 것이라 생각이 된다. 하지만 위젯의 공통 데이터 상태 관리는 provider라는 라이브러리가 존재 한다. 또한 provider는 InheritedWidget을 기반으로 한 상태관리 라이브러리 이기 때문에 해당 위젯을 직접적으로 사용하기 보다는 provider를 사용 하는것이 더 편리하다.
provider 이외에도 riverpod, getx, rxdart, bloc 등이 존재 하는데, 단순히 상태관리뿐 아니라 비동기 프로그래밍, 반응형 프로그래밍을 위한 라이브러리이기 때문에 다르다고 할 수 있다.
inheritedWidget을 기반으로 한 라이브러리 - provider, riverpod
Stream을 기반으로 한 비동기 처리 및 상태관리 - bloc, getx, rxdart
오늘은 inheritedWidget에 대하여 알아보았다. 실제 업무상 사용 예 대신에 주석의 몇가지 예시를 통해 알아보았으나 개념적 부분들은 충분히 이해 할 수 있을 것이라 생각한다.
'Weekly Flutter' 카테고리의 다른 글
[Flutter 주석 파헤치기] 03-1. Key (0) | 2023.03.01 |
---|---|
[Flutter Widget] 스크롤 가능한 레이아웃 만들기 - 1 (0) | 2023.02.22 |
[Flutter 아는 척하기] 플러터 선택의 이유 (0) | 2023.02.15 |
[Platform integration] 1. Method Channel 사용방법 (0) | 2023.02.08 |
[Flutter Widget] size를 줄수 있는 위젯과 size를 줄 수 없는 위젯 (0) | 2023.02.05 |