- Inherited Widget
- dependOnInheritedWidgetOfExactType()
- findAncestorWidgetOfExactType()
- findAncestorStateOfType()
State, Context, Inherited Widget 등 모두 플러터라는 프레임워크의 매우 중요한 오브젝트들이다.
플러터에 입문하게 되면 Provider, Riverpod, GetX 와 같은 상태관리 패키지를 활용한 데이터 제어를 먼저 접하게 된다.
많은 자료들이 이에 집중되어 있어, Inherited Widget 같은 개념은 쉽게 지나치게 된 것이 내가 느꼈던 아쉬움이다.
상태관리에서 setState 만큼이나 조상 격인 Inherited Widget을 알아보자.
💫 장바구니에 상품을 담고, 이를 장바구니 페이지 아래 어딘가 Widget A, D, F에서 모두 접근한다.
이 때 위젯 D가 B-C-D 순의 위젯트리를 가지고 있어서 장바구니 페이지의 state에 접근하려면 부모 인스턴스를 계속해서 자식에게 전달(drilling)해야하는 번거로움이 발생한다.
이를 Inherited Widget으로 말끔히 해결할 수 있다.
class Cart extends InheritedWidget {
const Cart({
Key? key,
required this.data,
required Widget child,
}) : super(key: key, child: child);
final List<Product> data;
static Cart of(BuildContext context) {
final Cart? result = context.dependOnInheritedWidgetOfExactType<Cart>();
assert(result != null, 'No Cart found in context');
return result!;
}
bool updateShouldNotify(Cart old) => data != old.data;
}
이제 장바구니에 접근해보자.
여기서 우리는 Cart class에 static 메써드인 of를 선언해뒀다.
context.dependOnInheritedWidgetOfExactType<Cart>()
는 현재 context에서 가장 가까운 Inherited Widget을 상속받은 Cart 클래스를 찾아서 리턴한다.
...
Cart(
data: Colors.green,
child: Builder(
builder: (BuildContext context) {
return Text(Cart.of(context).data.first.name);
},
),
...
Cart.of(context).data
로 쉽게 장바구니 리스트에 접근할 수 있다.
context.findAncestorWidgetOfExactType<Cart>()
는 현재 context에서 가장 가까운 Cart 클래스를 찾는다.
반면, dependOnInheritedWidgetOfExactType() 는 Inherited Widget을 상속받은 서브클래스들만 찾기 때문에 훨씬 비용 소모가 적은 방법이다.
특정 StatefulWidget의 State에 접근할 수 있도록 해준다.
만약 자식 위젯에서 부모 위젯의 상태를 변경하고 setState 해야 한다면?
부모 위젯 클래스에 findAncestorStateOfType() 를 static 메써드 of()로 선언해두고 쉽게 접근할 수 있다.
Parent.of(context).setState((){}); // 부모 내부에서 setState 호출
Parent.of(context).data; // 내부 변수에도 접근 가능
오늘도 한 조각 잘 먹고 갑니다 :)