Cause
Two things are missing: notifyListeners() is never called, and the badge widget may be reading with read instead of watch.
1. Mutate inside the model and notify
class CartModel extends ChangeNotifier {
final List<Item> _items = [];
List<Item> get items => List.unmodifiable(_items);
int get count => _items.length;
void add(Item item) {
_items.add(item);
notifyListeners();
}
}
Expose an unmodifiable view so widgets cannot change the list behind the model's back (that is exactly the bug in the snippet).
2. Use read for actions, watch for display
context.read<CartModel>().add(item);
final count = context.watch<CartModel>().count;
read never subscribes, watch subscribes and rebuilds. Calling watch inside onPressed throws in debug; calling read inside build silently stops updating.
3. Rebuild less with select or Consumer
final count = context.select<CartModel, int>((c) => c.count);
The widget now rebuilds only when count changes.
Common pitfalls
- The provider is created inside a widget that rebuilds (so a fresh model is made each time). Create it once above
MaterialApp with ChangeNotifierProvider(create: (_) => CartModel(), child: ...).
- Using
ChangeNotifierProvider.value for a new instance on each build leaks and resets state.
- Calling
notifyListeners() during build raises "setState() or markNeedsBuild() called during build".
There is a worked example in the DEV3 snippet library.