skills/flutter/references/best-practices-state.md

226 lines
4.5 KiB
Markdown

---
name: best-practices-state
description: Flutter state management best practices - when to use setState, state lifting, and state management patterns
---
# State Management Best Practices
Guidelines for managing state effectively in Flutter applications.
## When to Use setState
Use `setState()` for local widget state.
```dart
// ✅ Good - local UI state
class CounterWidget extends StatefulWidget {
@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'),
),
],
);
}
}
```
## State Lifting
Lift state to nearest common ancestor.
```dart
// ✅ Good - state lifted to parent
class ParentWidget extends StatefulWidget {
@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),
],
);
}
}
```
## ValueNotifier for Simple State
Use `ValueNotifier` for simple observable values.
```dart
// ✅ Good - simple observable state
class CounterModel {
final ValueNotifier<int> count = ValueNotifier<int>(0);
void increment() {
count.value++;
}
void dispose() {
count.dispose();
}
}
```
## ChangeNotifier for Complex State
Use `ChangeNotifier` for complex state with multiple properties.
```dart
// ✅ Good - complex state
class UserModel extends ChangeNotifier {
String _name = '';
String _email = '';
String get name => _name;
String get email => _email;
void updateName(String name) {
_name = name;
notifyListeners();
}
void updateEmail(String email) {
_email = email;
notifyListeners();
}
}
```
## Avoid Unnecessary Rebuilds
Split widgets to minimize rebuilds.
```dart
// ❌ Bad - entire widget rebuilds
class BadWidget extends StatefulWidget {
@override
State<BadWidget> createState() => _BadWidgetState();
}
class _BadWidgetState extends State<BadWidget> {
int _counter = 0;
@override
Widget build(BuildContext context) {
return Column(
children: [
ExpensiveWidget(), // Rebuilds unnecessarily
Text('Count: $_counter'),
ElevatedButton(
onPressed: () => setState(() => _counter++),
child: const Text('Increment'),
),
],
);
}
}
// ✅ Good - split widgets
class GoodWidget extends StatefulWidget {
@override
State<GoodWidget> createState() => _GoodWidgetState();
}
class _GoodWidgetState extends State<GoodWidget> {
int _counter = 0;
@override
Widget build(BuildContext context) {
return Column(
children: [
const ExpensiveWidget(), // const prevents rebuild
CounterDisplay(counter: _counter),
ElevatedButton(
onPressed: () => setState(() => _counter++),
child: const Text('Increment'),
),
],
);
}
}
```
## State Management Patterns
### Provider Pattern
```dart
// Use Provider package for app-wide state
ChangeNotifierProvider(
create: (_) => CounterModel(),
child: MyApp(),
)
```
### BLoC Pattern
```dart
// Use BLoC pattern for complex state logic
class CounterBloc {
final _counterController = StreamController<int>.broadcast();
Stream<int> get counter => _counterController.stream;
int _count = 0;
void increment() {
_count++;
_counterController.add(_count);
}
void dispose() {
_counterController.close();
}
}
```
## Key Points
- Use `setState()` for local widget state only
- Lift state to nearest common ancestor
- Use `ValueNotifier` for simple observable values
- Use `ChangeNotifier` for complex state
- Split widgets to minimize rebuilds
- Use `const` constructors when possible
- Consider state management packages for app-wide state
- Always dispose state management objects
- Avoid storing state in global variables
- Use appropriate pattern based on complexity
<!--
Source references:
- https://docs.flutter.dev/development/data-and-backend/state-mgmt
- https://docs.flutter.dev/development/data-and-backend/state-mgmt/simple
-->