Irbisa · Шпаргалка
Состояние на Provider
Пакет Provider, ChangeNotifier, Consumer, context.watch/read/select
Что такое
ChangeNotifierиChangeNotifierProvider? Напишите на них счётчик.class Counter extends ChangeNotifier { int _value = 0; int get value => _value; void increment() { _value++;…Нажатие на +1 не меняет число на экране, а в debug нажатие падает. Что не так с этим виджетом?
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'), ), ]); }}Что такое
MultiProviderи за что отвечает флагlazyу провайдера?void main() { runApp( MultiProvider( providers: [ Provider<ApiClient>(create: (_) => ApiClient()), ChangeNotifierProvider(…Переключатель ниже не двигается при нажатии, хотя
darkModeдействительно меняется. Почему?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, );}Чем отличаются
context.watch,context.read,context.selectиConsumer?class CartBadge extends StatelessWidget { const CartBadge({super.key}); @override Widget build(BuildContext context) { // rebuilds only when count changes, not when prices change…Чем отличаются
Provider,ChangeNotifierProvider,FutureProviderиStreamProvider?MultiProvider( providers: [ Provider<ApiClient>(create: (_) => ApiClient()), ChangeNotifierProvider(create: (_) => CartNotifier()), FutureProvider<RemoteConfig?>( create: (context) => context.read<ApiClient>().fetchConfig(),…Чем отличается
ChangeNotifierProvider(create: ...)отChangeNotifierProvider.valueи кто вызываетdisposeу объекта?// right: the provider owns it, creates once, disposes on unmountChangeNotifierProvider( create: (_) => CartNotifier(), child: const ShopApp(),)…Что делают
Selectorиcontext.selectи как они сокращают перестройки по сравнению сConsumer?// 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),…Найдите баг: после
add()новый товар так и не появляется в списке корзины, хотя нотифаер меняется.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)]);}Что такое
ProxyProviderи что сломается, еслиChangeNotifierProxyProvider.updateкаждый раз возвращает новый нотифаер?MultiProvider( providers: [ ChangeNotifierProvider(create: (_) => AuthNotifier()), // immutable service: a new instance per token is fine ProxyProvider<AuthNotifier, ApiService>(…Из-за чего возникает «A ChangeNotifier was used after being disposed» и как это предотвратить?
class FeedNotifier extends ChangeNotifier { FeedNotifier(this._repo) { _sub = _repo.updates().listen((_) => notifyListeners()); } final FeedRepository _repo;…Эта страница падает с «setState() or markNeedsBuild() called during build». Почему и где вместо этого вызывать
load()?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();}Диалог, открытый через
showDialog, выбрасываетProviderNotFoundException. Почему и как это исправить?// 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(…Где показывать snackbar или делать навигацию при изменении состояния нотифаера, если в Provider нет
BlocListener?class _CheckoutPageState extends State<CheckoutPage> { late final CheckoutNotifier _notifier; late CheckoutStatus _last; @override void initState() { super.initState();…Найдите баг: эта страница падает каждый раз, когда пользователь с неё уходит.
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(); }}Как тестировать экран, который зависит от Provider?
class MockCartApi extends Mock implements CartApi {} void main() { late MockCartApi api; setUp(() => api = MockCartApi());…Чем Riverpod отличается от Provider, какие проблемы Provider он решает и когда всё же стоит выбрать Provider?
Расскажите, что на самом деле происходит, когда виджет вызывает
context.watch<T>().После выхода одного пользователя и входа другого приложение всё ещё показывает данные первого. Как сбросить провайдеры, которые живут выше
MaterialApp?class SignedInScope extends StatelessWidget { const SignedInScope({super.key, required this.child}); final Widget child; @override Widget build(BuildContext context) {…Метод меняет десять полей и вызывает
notifyListeners()после каждого. Сколько перестроек виджетов это вызовет и во что это обходится на самом деле?Нотифаер над
MaterialAppтикает раз в секунду, на него подписаны несколько экранов, и чем глубже пользователь уходит в навигацию, тем сильнее тормозит приложение. Почему важна глубина стека?