Flutter InheritedWidget
Share data down the widget tree efficiently
🌳 What is InheritedWidget?
InheritedWidget is Flutter's low-level mechanism for propagating data down the widget tree. It allows child widgets to access shared data without passing it through constructors, making state management more efficient.
// Access inherited data
final data = MyInheritedWidget.of(context);
Key Concepts
Data Propagation
Share data down the tree
class MyInherited
extends InheritedWidget
Efficient Updates
Only rebuilds dependent widgets
@override
bool updateShouldNotify()
Context Access
Find data using context
MyWidget.of(context)
Foundation
Base for other state solutions
// Provider uses this
// Theme uses this
🔹 Basic InheritedWidget Example
Create a simple theme provider:
import 'package:flutter/material.dart';
// 1. Create InheritedWidget
class ThemeProvider extends InheritedWidget {
final Color primaryColor;
final Widget child;
ThemeProvider({
required this.primaryColor,
required this.child,
}) : super(child: child);
// 2. Provide access method
static ThemeProvider? of(BuildContext context) {
return context.dependOnInheritedWidgetOfExactType<ThemeProvider>();
}
// 3. Determine when to notify
@override
bool updateShouldNotify(ThemeProvider oldWidget) {
return primaryColor != oldWidget.primaryColor;
}
}
// 4. Use in widget tree
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return ThemeProvider(
primaryColor: Colors.blue,
child: MaterialApp(
home: HomePage(),
),
);
}
}
Output:
A theme provider that shares a primary color with all child widgets.
🔹 Accessing Inherited Data
Child widgets can access the shared data:
class HomePage extends StatelessWidget {
@override
Widget build(BuildContext context) {
// Access the inherited data
final theme = ThemeProvider.of(context);
return Scaffold(
appBar: AppBar(
title: Text('InheritedWidget Demo'),
backgroundColor: theme?.primaryColor,
),
body: Center(
child: Container(
width: 200,
height: 200,
color: theme?.primaryColor,
child: Center(
child: Text(
'Themed Box',
style: TextStyle(color: Colors.white),
),
),
),
),
);
}
}
Output:
A page with an AppBar and container both using the inherited primary color.
🔹 Counter with InheritedWidget
Manage counter state across widgets:
class CounterProvider extends InheritedWidget {
final int counter;
final Function() increment;
final Widget child;
CounterProvider({
required this.counter,
required this.increment,
required this.child,
}) : super(child: child);
static CounterProvider? of(BuildContext context) {
return context.dependOnInheritedWidgetOfExactType<CounterProvider>();
}
@override
bool updateShouldNotify(CounterProvider oldWidget) {
return counter != oldWidget.counter;
}
}
// Wrapper with state
class CounterWrapper extends StatefulWidget {
final Widget child;
CounterWrapper({required this.child});
@override
_CounterWrapperState createState() => _CounterWrapperState();
}
class _CounterWrapperState extends State<CounterWrapper> {
int _counter = 0;
void _increment() {
setState(() {
_counter++;
});
}
@override
Widget build(BuildContext context) {
return CounterProvider(
counter: _counter,
increment: _increment,
child: widget.child,
);
}
}
Output:
A counter provider that shares counter value and increment function with all descendants.
🔹 Using the Counter Provider
Access counter from any child widget:
class CounterDisplay extends StatelessWidget {
@override
Widget build(BuildContext context) {
final provider = CounterProvider.of(context);
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
'Count: ${provider?.counter}',
style: TextStyle(fontSize: 32),
),
SizedBox(height: 20),
ElevatedButton(
onPressed: provider?.increment,
child: Text('Increment'),
),
],
);
}
}
Output:
A widget displaying the counter value and a button to increment it.
🔹 When to Use InheritedWidget
✅ Good For:
- Sharing data across multiple widgets
- Theme and configuration data
- Building custom state management
- Learning Flutter internals
- Performance-critical applications
❌ Not Ideal For:
- Beginners (use Provider instead)
- Complex state logic
- When you need middleware
- Apps requiring time-travel debugging
🔹 Important Notes
Key Points:
- Low-level: InheritedWidget is the foundation for Provider, Theme, and MediaQuery
- Immutable: Data in InheritedWidget should be immutable
- Rebuild control: Use updateShouldNotify() to control rebuilds
- Context dependency: Widgets using .of(context) will rebuild when data changes
- Not for beginners: Consider using Provider package for easier state management