[Flutter 기초] InheritedWidget에 대해 알아보자

Yellowtoast·2023년 1월 31일
2

Flutter 기초

목록 보기
3/4
post-thumbnail

1. 왜 필요한가?

StatefulWidget과 StatelessWidget을 통해 화면을 구성하게 되었을 때, 변화가 필요한 위젯이 트리의 끝부분에 있다면 트리의 top에서 bottom까지 불필요한 데이터 전달이 일어나게 된다.

따라서, 변화가 필요한 위젯의 경우 트리를 통해 내려오는 데이터를 받는 대신, 바로 Tree 의 Top에 접근하여 바로 데이터를 가져오게 할 수 있도록 하는 것이 바로 Inherited Widget 이다.

Inherited Widget은 상태관리 라이브러리의 근간이라 할 수 있는 Provider의 핵심이므로 알아 둘 필요가 있다.

2. 간단한 동작 원리를 알아보자

먼저 InheritedWidget을 extends 하는 class를 만든다.
child 위젯은 반드시 포함해야 한다. InheritedWidget인 FrogColor의 자손이 되는 모든 위젯은, 해당 위젯의 필드에 접근할 수 있다.

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!;
  }

  
  bool updateShouldNotify(FrogColor oldWidget) => color != oldWidget.color;
}

위의 코드에서 볼 수 있듯이, InheritedWidget에서는 bool값을 리턴하는 updateShouldNotify를 override 한다. 여기서 updateShouldNotify 함수는 어떤 역할을 할까?

Whether the framework should notify widgets that inherit from this widget. When this widget is rebuilt, sometimes we need to rebuild the widgets that inherit from this widget but sometimes we do not. For example, if the data held by this widget is the same as the data held by oldWidget, then we do not need to rebuild the widgets that inherited the data held by oldWidget.
The framework distinguishes these cases by calling this function with the widget that previously occupied this location in the tree as an argument. The given widget is guaranteed to have the same runtimeType as this object.

updateShouldNotify는, 상속 받은 위젯이 있을 때 모든 상호아에서 다시 빌드 되는걸 방지하기 위해 있다. 빌드가 필요한 상황일 경우 true를, 빌드가 필요 없는 상황일 경우 false를 리턴하여 다시 재빌드되는 상황을 컨트롤한다.

다시 본론으로 돌아오자면, 보통 Inherited Widget을 만들 때 내부에 보통은 'of'라는 Static 함수를 선언해서 사용한다. 위에코드에도 있지만 다시 언급하자면 아래와 같은 형태이다.

  static FrogColor of(BuildContext context) {
    final FrogColor? result = maybeOf(context);
    assert(result != null, 'No FrogColor found in context');
    return result!;
  }

그리고 이 of 함수는 다른 위젯에서 아래와 같은 형태로 사용된다.

// continuing from previous example...
class MyPage extends StatelessWidget {
  const MyPage({super.key});

  
  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),
            );
          },
        ),
      ),
    );
  }
}

하지만 구현된 of 코드에 관심을 기울여야 한다. 상속받은 위젯을 접근하고 사용하려면 반드시 context에 접근해야 하며, 만약 이 FrogColor 위젯을 찾을 수 없는 경우 바로 오류를 발생시킨다. 이는 사용자가 FrogColor 위젯을 생성하지 않고(선언은 하였지만) 사용할 경우 컴파일타임에 어떤 오류도 발생시키지 못한다는 점이다.

  static FrogColor of(BuildContext context) {
    final FrogColor? result = maybeOf(context);
    assert(result != null, 'No FrogColor found in context');
    return result!;
  }
profile
Flutter App Developer

0개의 댓글