Irbisa · Cheatsheet
State with Provider
Provider package, ChangeNotifier, Consumer, context.watch/read/select
What are
ChangeNotifierandChangeNotifierProvider? Build a counter with them.class Counter extends ChangeNotifier { int _value = 0; int get value => _value; void increment() { _value++;…Tapping +1 never changes the number on screen, and in debug the tap throws. What is wrong with this widget?
class CounterView extends StatelessWidget { const CounterView({super.key}); @override Widget build(BuildContext context) { final counter = context.read<Counter>(); return Column(children: [ Text('${counter.value}'), ElevatedButton( onPressed: () => context.watch<Counter>().increment(), child: const Text('+1'), ), ]); }}What is
MultiProvider, and what does thelazyflag on a provider control?void main() { runApp( MultiProvider( providers: [ Provider<ApiClient>(create: (_) => ApiClient()), ChangeNotifierProvider(…The switch below never moves when tapped, although
darkModedoes change. Why?class Settings { bool darkMode = false;}// above the appProvider<Settings>(create: (_) => Settings(), child: const App());// in the settings screen@overrideWidget build(BuildContext context) { final settings = context.watch<Settings>(); return SwitchListTile( title: const Text('Dark mode'), value: settings.darkMode, onChanged: (v) => settings.darkMode = v, );}What is the difference between
context.watch,context.read,context.selectandConsumer?class CartBadge extends StatelessWidget { const CartBadge({super.key}); @override Widget build(BuildContext context) { // rebuilds only when count changes, not when prices change…What is the difference between
Provider,ChangeNotifierProvider,FutureProviderandStreamProvider?MultiProvider( providers: [ Provider<ApiClient>(create: (_) => ApiClient()), ChangeNotifierProvider(create: (_) => CartNotifier()), FutureProvider<RemoteConfig?>( create: (context) => context.read<ApiClient>().fetchConfig(),…What is the difference between
ChangeNotifierProvider(create: ...)andChangeNotifierProvider.value, and who disposes the object?// right: the provider owns it, creates once, disposes on unmountChangeNotifierProvider( create: (_) => CartNotifier(), child: const ShopApp(),)…What do
Selectorandcontext.selectdo, and how do they cut rebuilds compared withConsumer?// rebuilds only when the name changesfinal name = context.select<UserNotifier, String>((u) => u.name); // several fields: records compare by valuefinal (count, total) = context.select<CartNotifier, (int, double)>( (c) => (c.count, c.total),…Find the bug: after
add(), the cart list never shows the new item, although the notifier does change.class CartNotifier extends ChangeNotifier { final List<String> _items = []; List<String> get items => _items; void add(String item) { _items.add(item); notifyListeners(); }} // in CartList.buildWidget build(BuildContext context) { final items = context.select<CartNotifier, List<String>>((c) => c.items); return Column(children: [for (final name in items) Text(name)]);}What is
ProxyProvider, and what goes wrong ifChangeNotifierProxyProvider.updatereturns a new notifier every time?MultiProvider( providers: [ ChangeNotifierProvider(create: (_) => AuthNotifier()), // immutable service: a new instance per token is fine ProxyProvider<AuthNotifier, ApiService>(…What causes "A ChangeNotifier was used after being disposed", and how do you prevent it?
class FeedNotifier extends ChangeNotifier { FeedNotifier(this._repo) { _sub = _repo.updates().listen((_) => notifyListeners()); } final FeedRepository _repo;…This page crashes with "setState() or markNeedsBuild() called during build". Why, and where should
load()be called instead?class FeedNotifier extends ChangeNotifier { FeedNotifier(this._repo); final FeedRepository _repo; List<Post> posts = const []; Future<void> load() async { notifyListeners(); // e.g. show a spinner posts = await _repo.fetch(); notifyListeners(); }}// FeedList watches FeedNotifierWidget build(BuildContext context) { context.read<FeedNotifier>().load(); return const FeedList();}A dialog opened with
showDialogthrowsProviderNotFoundException. Why, and how do you fix it?// screen-scoped state: capture it, then re-expose inside the routeonPressed: () { final cart = context.read<CartNotifier>(); // still inside the page showDialog( context: context, builder: (_) => ChangeNotifierProvider<CartNotifier>.value(…Where do you show a snackbar or navigate when a notifier's state changes, given Provider has no
BlocListener?class _CheckoutPageState extends State<CheckoutPage> { late final CheckoutNotifier _notifier; late CheckoutStatus _last; @override void initState() { super.initState();…Find the bug: this page throws every time the user leaves it.
class _OrdersPageState extends State<OrdersPage> { @override void initState() { super.initState(); context.read<OrdersNotifier>().addListener(_onChanged); } void _onChanged() { if (!context.read<OrdersNotifier>().failed) return; ScaffoldMessenger.of(context).showSnackBar(const SnackBar(content: Text('Failed'))); } @override void dispose() { context.read<OrdersNotifier>().removeListener(_onChanged); super.dispose(); }}How do you test a screen that depends on Provider?
class MockCartApi extends Mock implements CartApi {} void main() { late MockCartApi api; setUp(() => api = MockCartApi());…How does Riverpod differ from Provider, which Provider problems does it fix, and when would you still pick Provider?
Walk me through what actually happens when a widget calls
context.watch<T>().After one user signs out and another signs in, the app still shows the first user's data. How do you reset providers that live above
MaterialApp?class SignedInScope extends StatelessWidget { const SignedInScope({super.key, required this.child}); final Widget child; @override Widget build(BuildContext context) {…A method mutates ten fields and calls
notifyListeners()after each one. How many widget rebuilds does that cause, and what does it really cost?A notifier above
MaterialAppticks once a second, several screens watch it, and the app gets janky the deeper users navigate. Why does stack depth matter?