Irbisa · Cheatsheet
State with Riverpod
Riverpod providers, AsyncNotifier, ref, code generation
Which provider types does Riverpod offer, and when do you pick
Notifier,AsyncNotifieror a plainFutureProvider?What is the difference between
ref.watch,ref.readandref.listen?class HomePage extends ConsumerWidget { const HomePage({super.key}); @override Widget build(BuildContext context, WidgetRef ref) { // watch: this widget rebuilds when the count changes…What is the difference between
ConsumerWidget,ConsumerStatefulWidgetand theConsumerbuilder?class ProductPage extends StatelessWidget { const ProductPage({super.key}); @override Widget build(BuildContext context) { return Scaffold(…What is the difference between
ref.invalidateandref.refresh?What is
AsyncValue, and how do you render its loading, error and data states?class ProfileView extends ConsumerWidget { const ProfileView({super.key}); @override Widget build(BuildContext context, WidgetRef ref) { final profile = ref.watch(profileProvider);…What is the
familymodifier, and what must be true of its argument?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>> {…How does
autoDisposework, and when do you needref.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(() {…How does Riverpod code generation (
@riverpod) work, and why use it?import 'package:riverpod_annotation/riverpod_annotation.dart'; part 'products.g.dart'; // A function: generates productProvider, a FutureProvider family@riverpod…How do you limit rebuilds with
select, and why does it depend on equality?// UiState is a freezed class: theme, sidebarOpen, unreadCount // wrong: rebuilds on every unread-count tickclass ThemeIconBad extends ConsumerWidget { const ThemeIconBad({super.key}); @override…Neither
addnoraddAgainupdates the cart badge on screen. What is Riverpod doing, and how do you fix it?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);This results screen fires a new search request on every rebuild and never leaves the loading state. What is wrong?
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)));Find the bug: tapping a filter chip highlights it, but the list only switches to the new filter after the user toggles a todo.
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)How do you trigger navigation, snackbars or dialogs from Riverpod state?
class CheckoutPage extends ConsumerWidget { const CheckoutPage({super.key}); @override Widget build(BuildContext context, WidgetRef ref) { ref.listen(orderProvider, (prev, next) {…A screen writes a provider's state from
initStateand Riverpod throws "Tried to modify a provider while the widget tree was building". Where does that write belong?// 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);…A provider needs data from two other async providers before it can compute anything. How do you write it without nesting
when()calls?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 {…Toggling a todo makes the whole list flash a full-screen spinner although the old rows are still in memory. Why, and how do you keep them on screen?
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);…How do you unit-test a Riverpod notifier with
ProviderContainer, and why can its state reset between two calls?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 says the cart total goes wrong after one specific navigation and nobody can reproduce it. How do you make Riverpod tell you which provider changed and when?
class StateLogger extends ProviderObserver { // Riverpod 3 signature; 2.x passed (provider, previous, next, container) @override void didUpdateProvider( ProviderObserverContext context, Object? previousValue,…How do
ProviderScopeoverrides work, and what does it take to scope a provider to a subtree?// Root: per-flavour config and test fakesvoid main() { runApp(ProviderScope( overrides: [ apiBaseUrlProvider.overrideWithValue(const String.fromEnvironment('API_URL')), ],…Your
AsyncNotifierawaits a slow request and then touchesref; the user pops the screen mid-flight. What breaks, and how do you write it safely?class UploadNotifier extends AsyncNotifier<Upload> { @override Future<Upload> build() async { final token = CancelToken(); ref.onDispose(token.cancel); // an abandoned request dies with the provider…A user is halfway through editing a form held in an
AsyncNotifierwhen the session token refreshes, and their edits vanish. What happened?After the Riverpod 3 upgrade, a screen whose request returns 400 keeps re-firing that request every few seconds. What is doing that, and how do you stop it?
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,…What changed in Riverpod 3, and what breaks when you upgrade a 2.x app?
A foreground push handler and your
main()bootstrap both need the repositories the app reads through providers. How do you share them without two copies of the state?Future<void> main() async { WidgetsFlutterBinding.ensureInitialized(); // one container: built in main(), warmed up, then handed to the tree final container = ProviderContainer( overrides: […Riverpod asks you to declare providers as top-level
finalvariables. Isn't that exactly the global mutable state everyone warns about?