4.9 KiB
4.9 KiB
| name | description |
|---|---|
| core-state-management | Flutter state management patterns - setState, StatefulWidget, ValueNotifier, ChangeNotifier, and state lifting |
State Management
Flutter provides several mechanisms for managing state in applications. Choose the appropriate pattern based on your needs.
setState (Local State)
Use setState() for local state within a StatefulWidget. This is the simplest form of state management.
class CounterWidget extends StatefulWidget {
const CounterWidget({super.key});
@override
State<CounterWidget> createState() => _CounterWidgetState();
}
class _CounterWidgetState extends State<CounterWidget> {
int _counter = 0;
void _increment() {
setState(() {
_counter++;
});
}
@override
Widget build(BuildContext context) {
return Column(
children: [
Text('Count: $_counter'),
ElevatedButton(
onPressed: _increment,
child: const Text('Increment'),
),
],
);
}
}
ValueNotifier
Use ValueNotifier for simple value changes that need to be observed by multiple widgets.
class CounterModel {
final ValueNotifier<int> count = ValueNotifier<int>(0);
void increment() {
count.value++;
}
void dispose() {
count.dispose();
}
}
// Usage
class CounterWidget extends StatelessWidget {
final CounterModel model;
const CounterWidget({super.key, required this.model});
@override
Widget build(BuildContext context) {
return ValueListenableBuilder<int>(
valueListenable: model.count,
builder: (context, count, child) {
return Text('Count: $count');
},
);
}
}
ChangeNotifier
Use ChangeNotifier for more complex state that needs to notify multiple listeners.
class CounterModel extends ChangeNotifier {
int _count = 0;
int get count => _count;
void increment() {
_count++;
notifyListeners();
}
}
// Usage with AnimatedBuilder or ListenableBuilder
class CounterWidget extends StatelessWidget {
final CounterModel model;
const CounterWidget({super.key, required this.model});
@override
Widget build(BuildContext context) {
return ListenableBuilder(
listenable: model,
builder: (context, child) {
return Text('Count: ${model.count}');
},
);
}
}
State Lifting
Lift state up to the nearest common ancestor when multiple widgets need to share state.
class ParentWidget extends StatefulWidget {
const ParentWidget({super.key});
@override
State<ParentWidget> createState() => _ParentWidgetState();
}
class _ParentWidgetState extends State<ParentWidget> {
int _counter = 0;
void _increment() {
setState(() {
_counter++;
});
}
@override
Widget build(BuildContext context) {
return Column(
children: [
DisplayWidget(counter: _counter),
ControlWidget(onIncrement: _increment),
],
);
}
}
class DisplayWidget extends StatelessWidget {
final int counter;
const DisplayWidget({super.key, required this.counter});
@override
Widget build(BuildContext context) {
return Text('Count: $counter');
}
}
class ControlWidget extends StatelessWidget {
final VoidCallback onIncrement;
const ControlWidget({super.key, required this.onIncrement});
@override
Widget build(BuildContext context) {
return ElevatedButton(
onPressed: onIncrement,
child: const Text('Increment'),
);
}
}
InheritedWidget
Use InheritedWidget to provide state to descendant widgets without passing it explicitly.
class CounterInherited extends InheritedWidget {
final int count;
final VoidCallback increment;
const CounterInherited({
super.key,
required this.count,
required this.increment,
required super.child,
});
static CounterInherited? of(BuildContext context) {
return context.dependOnInheritedWidgetOfExactType<CounterInherited>();
}
@override
bool updateShouldNotify(CounterInherited oldWidget) {
return count != oldWidget.count;
}
}
// Usage
class CounterDisplay extends StatelessWidget {
const CounterDisplay({super.key});
@override
Widget build(BuildContext context) {
final counter = CounterInherited.of(context);
return Text('Count: ${counter?.count ?? 0}');
}
}
Key Points
- Use
setState()for local state within a single widget - Use
ValueNotifierfor simple observable values - Use
ChangeNotifierfor complex state with multiple properties - Lift state up to share it between widgets
- Use
InheritedWidgetto provide state to widget subtrees - Always dispose
ValueNotifierandChangeNotifierto prevent memory leaks - Consider using state management packages (Provider, Riverpod, Bloc) for larger apps