Teile den Anwendungszustand mit ChangeNotifier und Provider und beherrsche watch, read und select für gezielte Rebuilds.
Diese Lektion in Kodokon öffnensetState genügt, solange der Zustand mit einem einzigen Bildschirm lebt und stirbt. Sobald Daten geteilt werden - Warenkorb, Sitzung, Einstellungen - wird das Durchreichen von Konstruktor zu Konstruktor unbeherrschbar. ChangeNotifier liefert das minimale Observable des SDK; provider injiziert es in den Baum und baut nur die abonnierten Widgets neu. Im Vergleich zu Riverpod oder Bloc bleibt dieses Duo am leichtesten überprüfbar: wenig Magie, eine einzige Abhängigkeit, ein Mechanismus, den du in einem Satz erklären kannst.
flutter pub add providerEin gut entworfener Notifier kapselt: private Felder, nur lesende Getter, Änderungen ausschließlich über Methoden, die mit notifyListeners() enden. Genau dieser Vertrag garantiert, dass keine Zustandsänderung an der UI vorbeirutscht.
import 'package:flutter/foundation.dart';
class CartModel extends ChangeNotifier {
final List<String> _items = [];
List<String> get items => List.unmodifiable(_items);
int get count => _items.length;
void add(String item) {
_items.add(item);
notifyListeners();
}
void remove(String item) {
_items.remove(item);
notifyListeners();
}
}Drei Einstiegspunkte, drei Verwendungen. context.watch<T>() abonniert das Widget: Es wird bei jedem notifyListeners neu gebaut. context.read<T>() liest, ohne zu abonnieren: Es ist das Werkzeug für Callbacks wie onPressed. context.select<T, R>() abonniert nur eine Projektion: Das Widget wird nur dann neu gebaut, wenn sich genau dieser Wert ändert. Goldene Regel: watch und select nur in build, read in den Handlern - niemals umgekehrt.
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
class CounterModel extends ChangeNotifier {
int _value = 0;
int get value => _value;
void increment() {
_value++;
notifyListeners();
}
}
void main() {
runApp(
ChangeNotifierProvider(
create: (_) => CounterModel(),
child: const CounterApp(),
),
);
}
class CounterApp extends StatelessWidget {
const CounterApp({super.key});
@override
Widget build(BuildContext context) {
final value = context.watch<CounterModel>().value;
return MaterialApp(
home: Scaffold(
body: Center(child: Text('Count: $value')),
floatingActionButton: FloatingActionButton(
onPressed: () =>
context.read<CounterModel>().increment(),
child: const Icon(Icons.add),
),
),
);
}
}import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
class CartModel extends ChangeNotifier {
final List<String> _items = [];
int get count => _items.length;
}
class CartBadge extends StatelessWidget {
const CartBadge({super.key});
@override
Widget build(BuildContext context) {
final count = context.select(
(CartModel cart) => cart.count,
);
return Badge(
label: Text('$count'),
child: const Icon(Icons.shopping_cart),
);
}
}
onPressed ein cart.add(...) aus, ohne ein unnötiges Abonnement zu erzeugen?context.watch<CartModel>().add(...)context.read<CartModel>().add(...)context.select((CartModel c) => c.add(...))notifyListeners() aus?List.unmodifiable(_items) statt _items direkt nach außen geben?notifyListeners und damit ohne Rebuild verändern würde.