Irbisa · Шпаргалка
Состояние на Riverpod
Провайдеры Riverpod, AsyncNotifier, ref, кодогенерация
Какие типы провайдеров есть в Riverpod и когда выбирать
Notifier,AsyncNotifierили обычныйFutureProvider?Чем отличаются
ref.watch,ref.readиref.listen?class HomePage extends ConsumerWidget { const HomePage({super.key}); @override Widget build(BuildContext context, WidgetRef ref) { // watch: this widget rebuilds when the count changes…Чем отличаются
ConsumerWidget,ConsumerStatefulWidgetи билдерConsumer?class ProductPage extends StatelessWidget { const ProductPage({super.key}); @override Widget build(BuildContext context) { return Scaffold(…Чем отличаются
ref.invalidateиref.refresh?Что такое
AsyncValueи как отрисовать его состояния загрузки, ошибки и данных?class ProfileView extends ConsumerWidget { const ProfileView({super.key}); @override Widget build(BuildContext context, WidgetRef ref) { final profile = ref.watch(profileProvider);…Что такое модификатор
familyи каким должен быть его аргумент?final productProvider = FutureProvider.autoDispose.family<Product, int>( (ref, id) => ref.watch(productRepositoryProvider).getProduct(id),); // A family notifier receives its argument through the constructor (Riverpod 3)class Basket extends Notifier<List<Item>> {…Как работает
autoDisposeи когда нуженref.keepAlive()?final searchProvider = FutureProvider.autoDispose.family<List<Hit>, String>((ref, query) async { // keep results for 5 minutes after the last listener leaves final link = ref.keepAlive(); Timer? timer; ref.onCancel(() {…Как работает кодогенерация Riverpod (
@riverpod) и зачем она нужна?import 'package:riverpod_annotation/riverpod_annotation.dart'; part 'products.g.dart'; // A function: generates productProvider, a FutureProvider family@riverpod…Как ограничить ребилды через
selectи почему это зависит от равенства?// UiState is a freezed class: theme, sidebarOpen, unreadCount // wrong: rebuilds on every unread-count tickclass ThemeIconBad extends ConsumerWidget { const ThemeIconBad({super.key}); @override…Ни
add, ниaddAgainне обновляют бейдж корзины на экране. Что делает Riverpod и как это исправить?class Cart extends Notifier<List<Item>> { @override List<Item> build() => []; void add(Item item) { state.add(item); } void addAgain(Item item) { state = state..add(item); }} final cartProvider = NotifierProvider<Cart, List<Item>>(Cart.new);Этот экран результатов отправляет новый поисковый запрос на каждом ребилде и никогда не выходит из загрузки. Что не так?
class SearchQuery { SearchQuery(this.text, this.page); final String text; final int page;} final searchProvider = FutureProvider.autoDispose .family<List<Hit>, SearchQuery>( (ref, q) => ref.watch(apiProvider).search(q.text, q.page),); // inside ResultsView.build(context, ref):final hits = ref.watch(searchProvider(SearchQuery(text, 1)));Найдите баг: чип фильтра при нажатии подсвечивается, но список переключается на новый фильтр, только когда пользователь отметит какую-нибудь задачу.
final filterProvider = NotifierProvider<FilterNotifier, Filter>(FilterNotifier.new); final visibleTodosProvider = Provider<List<Todo>>((ref) { final todos = ref.watch(todosProvider); final filter = ref.read(filterProvider); return switch (filter) { Filter.all => todos, Filter.active => todos.where((t) => !t.done).toList(), Filter.done => todos.where((t) => t.done).toList(), };}); // a chip's onSelected: ref.read(filterProvider.notifier).set(f)Как запускать навигацию, снекбары или диалоги по состоянию Riverpod?
class CheckoutPage extends ConsumerWidget { const CheckoutPage({super.key}); @override Widget build(BuildContext context, WidgetRef ref) { ref.listen(orderProvider, (prev, next) {…Экран пишет состояние провайдера из
initState, и Riverpod бросает «Tried to modify a provider while the widget tree was building». Где должна быть эта запись?// wrong: throws "Tried to modify a provider while the widget tree was building"class _FilterScreenState extends ConsumerState<FilterScreen> { @override void initState() { super.initState(); ref.read(filterProvider.notifier).set(widget.initial);…Провайдеру для вычислений нужны данные из двух других асинхронных провайдеров. Как написать его без вложенных вызовов
when()?final userProvider = FutureProvider<User>((ref) => ref.watch(apiProvider).me());final settingsProvider = FutureProvider<Settings>((ref) => ref.watch(apiProvider).settings()); // right: await .future, and one AsyncValue comes outfinal dashboardProvider = FutureProvider<Dashboard>((ref) async {…Переключение задачи заставляет весь список мигнуть полноэкранным спиннером, хотя старые строки ещё в памяти. Почему и как оставить их на экране?
class TodosNotifier extends AsyncNotifier<List<Todo>> { @override Future<List<Todo>> build() => ref.watch(apiProvider).fetchTodos(); Future<List<Todo>> _toggle(Todo t) async { await ref.read(apiProvider).setDone(t.id, !t.done);…Как юнит-тестировать нотифаер Riverpod через
ProviderContainerи почему его состояние может сброситься между двумя вызовами?class Cart extends AsyncNotifier<List<Item>> { @override Future<List<Item>> build() => ref.watch(cartRepoProvider).load(); Future<void> addItem(Item i) async { await ref.read(cartRepoProvider).save(i);…QA сообщает, что сумма корзины ломается после одного конкретного перехода, и никто не может воспроизвести. Как заставить Riverpod рассказать, какой провайдер изменился и когда?
class StateLogger extends ProviderObserver { // Riverpod 3 signature; 2.x passed (provider, previous, next, container) @override void didUpdateProvider( ProviderObserverContext context, Object? previousValue,…Как работают override в
ProviderScopeи что нужно, чтобы ограничить провайдер поддеревом?// Root: per-flavour config and test fakesvoid main() { runApp(ProviderScope( overrides: [ apiBaseUrlProvider.overrideWithValue(const String.fromEnvironment('API_URL')), ],…Ваш
AsyncNotifierждёт медленный запрос, а потом трогаетref; пользователь закрывает экран посреди запроса. Что ломается и как написать это безопасно?class UploadNotifier extends AsyncNotifier<Upload> { @override Future<Upload> build() async { final token = CancelToken(); ref.onDispose(token.cancel); // an abandoned request dies with the provider…Пользователь наполовину заполнил форму, которая хранится в
AsyncNotifier, обновился токен сессии, и его правки пропали. Что произошло?После перехода на Riverpod 3 экран, чей запрос возвращает 400, каждые несколько секунд отправляет его снова. Кто это делает и как это остановить?
Duration? retryPolicy(int retryCount, Object error) { if (retryCount >= 3) return null; // give up, show the error UI if (error is ProviderException) return null; // the source retries itself final transient = switch (error) { DioException(:final response?) => (response.statusCode ?? 0) >= 500,…Что изменилось в Riverpod 3 и что ломается при обновлении приложения с 2.x?
Обработчику пушей на переднем плане и бутстрапу в
main()нужны те же репозитории, что приложение читает через провайдеры. Как их разделить, не получив две копии состояния?Future<void> main() async { WidgetsFlutterBinding.ensureInitialized(); // one container: built in main(), warmed up, then handed to the tree final container = ProviderContainer( overrides: […Riverpod просит объявлять провайдеры как top-level
finalпеременные. Разве это не то самое глобальное изменяемое состояние, от которого все предостерегают?