InheritedWidget Internals

Medium PriorityAsked in ~50% of mid-level interviews

4 min read

State Management

InheritedWidget is Flutter's built-in way to share data down the widget tree. The foundation that Provider, Theme, MediaQuery and Navigator are all built upon.

It works in two steps: widgets subscribe using dependOnInheritedWidgetOfExactType<T>(), and later when updateShouldNotify returns true, only those subscribed widget gets rebuild.

1. Register — when a widget calls dependOnInheritedWidgetOfExactType<T>(), Flutter finds the nearest InheritedWidget and registers that widget as a dependent.

2. Notify — when the InheritedWidget updates, Flutter calls updateShouldNotify(). If it returns true, only the registered dependents are rebuilt.

StepWhere it lives
Lookup an InheritedWidgetElement._inheritedElements[T]
Register a dependentAdd Element to dependents list
Notify on changeWalk dependents list

The framework can do this efficiently because each Element keeps an inherited-widget cache updated as it's mounted into the tree.


Code in action — a mini Provider clone

class CounterProvider extends InheritedWidget {
  final int counter;
 
  const CounterProvider({
    super.key,
    required super.child,
    required this.counter,
  });
 
  @override
  bool updateShouldNotify(CounterProvider oldWidget) {
    return counter != oldWidget.counter;
  }
 
/// Registers a dependency.
  static CounterProvider? of(BuildContext context) {
    return context.dependOnInheritedWidgetOfExactType<CounterProvider>();
  }
}
 
 
 
/// Consumer
class CounterText extends StatelessWidget {
  const CounterText({super.key});
 
  @override
  Widget build(BuildContext context) {
    final count = CounterProvider.of(context).count; // registers dependency
 
    print('CounterText rebuilt');
 
    return Text(
      'Count: $count',
      style: const TextStyle(
        fontSize: 32,
        fontWeight: FontWeight.bold,
      ),
    );
  }
}

That's all Provider is, with extra ergonomics on top.


Common mistakes to avoid

// ❌ updateShouldNotify => true always — every parent rebuild rebuilds all dependents
@override
bool updateShouldNotify(_) => true;
// ✅ Compare meaningfully
 
// ❌ Reading from InheritedWidget in initState with dependOn... — partially-wired context
@override
void initState() {
  super.initState();
  final t = Theme.of(context);            // might miss future updates
}
// ✅ Read in didChangeDependencies, OR use getInheritedWidgetOfExactType for a one-shot read
 
// ❌ Storing mutable state directly in the InheritedWidget
class Cart extends InheritedWidget { List<Item> items = []; ... }
// items.add(...) mutates in place → updateShouldNotify can't detect it
// ✅ Wrap mutable state in a StatefulWidget above the InheritedWidget,
//    and rebuild the InheritedWidget with new field values
 
// ❌ Multiple InheritedWidgets of the same type stacked
// .of(context) finds the NEAREST — subtle bugs if you didn't intend nesting
 
// ❌ Forgetting that the same .of() call in different subtrees may yield different widgets
// That's a feature (scoped overrides) — but easy to forget

Interview follow-ups

  1. What's the time complexity of finding an InheritedWidget? O(1). Each Element keeps an _inheritedElements map keyed by runtime type, populated as the Element is mounted. dependOnInheritedWidgetOfExactType<T>() is a single map lookup — not a tree walk.

  2. How does Flutter know which widgets depend on an InheritedWidget? Each InheritedElement maintains a _dependents set. When a descendant calls dependOnInheritedWidgetOfExactType<T>, the framework adds that descendant's Element to T's _dependents. On updateShouldNotify returning true, Flutter walks that set and marks each dependent dirty.

  3. Why is updateShouldNotify separate from constructor equality? Because two InheritedWidget instances with equal fields are still different objects — the default == check wouldn't help. updateShouldNotify lets you opt into custom equality semantics for change detection, independent of the widget's identity.


How helpful was this content?

Please sign in to rate this article.