What is an `InheritedWidget` and why is it important for state management?
Show answer — try answering out loud first
An InheritedWidget is a special widget that propagates data down the tree efficiently, so that any descendant widget can read it with .of(context) without passing it manually through every constructor. It's the foundation that Theme, MediaQuery, Provider, and many state solutions are built on.
Imagine some data (the theme, the logged-in user) is needed by widgets deep in the tree. Passing it as a parameter at every level is tedious and fragile (that's called prop drilling).
An InheritedWidget solves it: you place it high in the tree and any descendant accesses it with AppData.of(context). When the InheritedWidget changes, Flutter automatically rebuilds only the widgets that depend on it (the ones that called .of(context)), not the whole tree.
That's why Theme.of(context) and MediaQuery.of(context) work: under the hood they're InheritedWidgets. Almost nobody writes one by hand these days; people use Provider/Riverpod, which wrap it, but understanding this is key in interviews.
import 'package:flutter/material.dart';
// An InheritedWidget that exposes a color to its descendants
class AppColor extends InheritedWidget {
final Color color;
const AppColor({
super.key,
required this.color,
required super.child,
});
// The typical access: AppColor.of(context)
static AppColor of(BuildContext context) {
final result =
context.dependOnInheritedWidgetOfExactType<AppColor>();
assert(result != null, 'No AppColor was found in the tree');
return result!;
}
// Tells Flutter when to rebuild the widgets that depend on it
@override
bool updateShouldNotify(AppColor oldWidget) => color != oldWidget.color;
}
// A descendant that reads the color without receiving it as a parameter
class LittleBox extends StatelessWidget {
const LittleBox({super.key});
@override
Widget build(BuildContext context) {
final color = AppColor.of(context).color;
return Container(width: 50, height: 50, color: color);
}
}
Not implementing updateShouldNotify correctly. That method decides whether the dependent widgets should rebuild when the InheritedWidget changes. If you always return true, you rebuild too much; if you always return false, the UI never reacts to changes. It should compare the old value with the new one.
"An
InheritedWidgetpropagates data down the tree efficiently, so that any descendant can read it with.of(context)instead of passing it as a parameter at every level. When it changes, Flutter rebuilds only the widgets that depend on it. It's the foundation ofTheme,MediaQuery, and solutions like Provider. I rarely write one by hand, but understanding it helps me know how those libraries work under the hood. The key piece isupdateShouldNotify, which decides when to notify the dependents."
How does Flutter rebuild only the widgets that use an InheritedWidget and not the whole tree?
See answer
When a widget calls dependOnInheritedWidgetOfExactType (which is what .of(context) does internally), Flutter registers that widget as a dependent of the InheritedWidget. When it changes, and if updateShouldNotify returns true, Flutter rebuilds only the elements registered as dependents, not the entire tree. That's why it's efficient.