Inherited Widgets
Sprout lets the user choose whether water is measured in millilitres or cups. The widget that prints "250 ml" sits five levels down the tree. Passing the unit through every constructor on the way means four widgets carry a value they never use. Flutter has a better route.
The rule
Put data above the tree; any widget below asks for it with
of(context).
An InheritedWidget holds data and makes it reachable from every widget beneath it.
class WaterUnits extends InheritedWidget {
const WaterUnits({super.key, required this.unit, required super.child});
final String unit; // 'ml' or 'cups'
static WaterUnits of(BuildContext context) =>
context.dependOnInheritedWidgetOfExactType<WaterUnits>()!;
@override
bool updateShouldNotify(WaterUnits oldWidget) => oldWidget.unit != unit;
}- Place it high up:
WaterUnits(unit: 'ml', child: SproutHome()). - Any widget below reads it:
WaterUnits.of(context).unit. - Reading it with
dependOnInheritedWidgetOfExactTypealso subscribes that widget: when a newWaterUnitsarrives with a different unit, the readers rebuild. updateShouldNotifydecides whether a change is worth rebuilding the readers for.
You already use this pattern. Theme.of(context) and MediaQuery.of(context) are built on inherited widgets, which is why a widget that reads the theme updates when the theme changes. Popular state-management packages such as Provider are also built on top of it.
The shortcut
Read X.of(context) as "walk up from here and find the nearest X".
Start at the widget
AmountLabelcallsWaterUnits.of(context). Itscontextis its position in the tree.
The trap is calling of(context) from a widget that is above the inherited widget, or with the context of the very widget that creates it. The walk goes up, so it finds nothing, and the ! throws.
Drills
Answer fast — trust the rule.
What problem do inherited widgets mainly solve?
Which call finds the nearest WaterUnits and subscribes to its changes?
A widget placed above WaterUnits calls WaterUnits.of(context). What happens?
What does updateShouldNotify returning false mean?
Which of these is built on an inherited widget?
Remember
- Put data above the tree; any widget below asks for it with
of(context). X.of(context)means "walk up from here and find the nearest X", and subscribe.- Trap: looking up from a context that is not below the inherited widget.
