Provider and ChangeNotifier
Provider is a package that puts a convenient API over InheritedWidget, and it was the choice recommended in Flutter's own docs for a long time. It has three parts:
- `ChangeNotifier` — the class holding your state; it calls
notifyListeners()when something changes - `ChangeNotifierProvider` — puts that object into the tree and manages its lifetime (disposing it for you)
- `Consumer` / `context.watch` / `context.read` — the ways to read it
The distinction that matters: `watch` subscribes (rebuilds on change), `read` does not (a one-off read). Inside callbacks — an onPressed, say — you always use read.
| Way to read | Subscribes? | When to use |
|---|---|---|
| `context.watch<T>()` | Yes | Inside `build`, when displaying the value |
| `context.read<T>()` | No | Inside a callback calling a method (`onPressed`) |
| `Consumer<T>` | Yes, but only its own builder | When you want to narrow the rebuild area |
| `Selector<T, R>` | Yes, only to the selected slice | When you depend on one field of a large object |
Interview tip. Two mistakes come up constantly. First: using context.read in build and then wondering why the UI does not update — read does not subscribe. Second: calling context.watch inside onPressed, which creates a pointless subscription and makes Flutter complain. The rule is simple: watch in `build`, read in callbacks.
📚 Sources and documentation
- provider packageofficialpub.dev
The README lays out `watch` vs `read` vs `select` and the common mistakes.
- Simple app state managementofficialdocs.flutter.dev
- State management optionsofficialdocs.flutter.dev