### Install and Run Riverpod Migration CLI Source: https://riverpod.dev/docs/migration/0.14.0_to_1.0.0 Commands to install the Riverpod migration tool globally and execute the migration process on an existing project. ```bash dart pub global activate riverpod_cli riverpod --help riverpod migrate ``` -------------------------------- ### Install Riverpod CLI Migration Tool Source: https://riverpod.dev/docs/migration/0.13.0_to_0.14.0 Command to install the Riverpod CLI tool globally, which assists in migrating projects to the new Riverpod syntax. ```bash dart pub global activate riverpod_cli ``` -------------------------------- ### Example: Using Generator - Riverpod Stream Source: https://riverpod.dev/docs/introduction/getting_started Demonstrates the usage of the `riverpodStream` generator for creating Riverpod streams. ```dart riverpodStream ``` -------------------------------- ### ProviderObserver Usage and Example Source: https://riverpod.dev/docs/concepts2/observers Demonstrates how to extend ProviderObserver to log provider state changes and how to integrate it into the application using ProviderScope. ```APIDOC ## ProviderObserver ### Description A ProviderObserver is an object used to observe provider lifecycle events in the application. They are generally used for logging, analytics, or debugging purposes. ### Usage To use a ProviderObserver, you need to extend the class and override the life-cycles you want to observe. There are many methods available. It is recommended to check its documentation for more details. ### Example: Logger The following observer logs all state changes of any provider in the application: ```dart // A basic logger, which logs any state changes. final class Logger extends ProviderObserver { @override void didUpdateProvider( ProviderObserverContext context, Object? previousValue, Object? newValue, ) { print(''' { "provider": "${context.provider}", "newValue": "$newValue", "mutation": "${context.mutation}" }'''); } } void main() { runApp( ProviderScope( // ProviderObservers are used by passing them to ProviderScope/ProviderContainer observers: [ // Adding ProviderScope enables Riverpod for the entire project // Adding our Logger to the list of observers Logger(), ], child: const MyApp(), ), ); } ``` ### Log Output Example ```json { "provider": "Provider", "newValue": "1" } ``` ### Naming Providers for Better Debugging To improve debugging, you can optionally give your providers a name: ```dart final myProvider = Provider((ref) => 0, name: 'MyProvider'); ``` With this change, the log becomes: ```json { "provider": "MyProvider", "newValue": "1" } ``` **Note**: When using code-generation, a name is automatically assigned to providers. **Important**: If the state of a provider is mutated, (typically Lists, combined with Ref.notifyListeners), it is likely that `didUpdateProvider` will receive `previousValue` and `newValue` as the same value. This happens because Dart updates objects by "reference". If you want to change this, you will have to clone your objects before mutating them. ``` -------------------------------- ### Setup JsonSqFliteStorage and Todo Provider Source: https://riverpod.dev/docs/whats_new Demonstrates initializing JsonSqFliteStorage and defining a Todo class for offline persistence without code generation. The storage provider should be shared across other providers. ```dart // A example showcasing JsonSqFliteStorage without code generation. final storageProvider = FutureProvider((ref) async { // Initialize SQFlite. We should share the Storage instance between providers. return JsonSqFliteStorage.open( join(await getDatabasesPath(), 'riverpod.db'), ); }); /// A serializable Todo class. class Todo { const Todo({ required this.id, required this.description, required this.completed, }); Todo.fromJson(Map json) : id = json['id'] as int, description = json['description'] as String, completed = json['completed'] as bool; final int id; final String description; final bool completed; Map toJson() { return { 'id': id, 'description': description, 'completed': completed, }; } } ``` ```dart final todosProvider = AsyncNotifierProvider>(TodosNotifier.new); class TodosNotifier extends AsyncNotifier>{ @override FutureOr> build() async { // We call persist at the start of our 'build' method. // This will: // - Read the DB and update the state with the persisted value the first // time this method executes. // - Listen to changes on this provider and write those changes to the DB. persist( // We pass our JsonSqFliteStorage instance. No need to "await" the Future. // Riverpod will take care of that. ref.watch(storageProvider.future), // A unique key for this state. // No other provider should use the same key. key: 'todos', // By default, state is cached offline only for 2 days. // We can optionally uncomment the following line to change cache duration. // options: const StorageOptions(cacheTime: StorageCacheTime.unsafe_forever), encode: jsonEncode, decode: (json) { final decoded = jsonDecode(json) as List; return decoded .map((e) => Todo.fromJson(e as Map)) .toList(); }, ); // We asynchronously fetch todos from the server. // During the await, the persisted todo list will be available. // After the network request completes, the server state will take precedence // over the persisted state. final todos = await fetchTodos(); return todos; } Future add(Todo todo) async { // When modifying the state, no need for any extra logic to persist the change. // Riverpod will automatically cache the new state and write it to the DB. state = AsyncData([...await future, todo]); } } ``` -------------------------------- ### Setup JsonSqFliteStorage and Todo Provider with Code Generation Source: https://riverpod.dev/docs/whats_new Shows how to set up offline persistence using code generation, including the storage provider, a Freezed-based Todo class, and the annotated TodosNotifier. ```dart @riverpod Future storage(Ref ref) async { // Initialize SQFlite. We should share the Storage instance between providers. return JsonSqFliteStorage.open( join(await getDatabasesPath(), 'riverpod.db'), ); } ``` ```dart /// A serializable Todo class. We're using Freezed for simple serialization. @freezed abstract class Todo with _$Todo { const factory Todo({ required int id, required String description, required bool completed, }) = _Todo; factory Todo.fromJson(Map json) => _$TodoFromJson(json); } ``` ```dart @riverpod @JsonPersist() class TodosNotifier extends _$TodosNotifier { @override FutureOr> build() async { // We call persist at the start of our 'build' method. // This will: // - Read the DB and update the state with the persisted value the first // time this method executes. // - Listen to changes on this provider and write those changes to the DB. persist( // We pass our JsonSqFliteStorage instance. No need to "await" the Future. // Riverpod will take care of that. ref.watch(storageProvider.future), // By default, state is cached offline only for 2 days. // We can optionally uncomment the following line to change cache duration. ``` -------------------------------- ### Hello World with Riverpod Generator Source: https://riverpod.dev/docs/introduction/getting_started This example utilizes riverpod_annotation to generate Riverpod providers. It simplifies provider creation by using annotations, reducing boilerplate code. ```dart import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:riverpod_annotation/riverpod_annotation.dart'; part 'main.g.dart'; // We create a "provider", which will store a value (here "Hello world"). // By using a provider, this allows us to mock/override the value exposed. @riverpod String helloWorld(Ref ref) { return 'Hello world'; } void main() { runApp( // For widgets to be able to read providers, we need to wrap the entire // application in a "ProviderScope" widget. // This is where the state of our providers will be stored. ProviderScope( child: MyApp(), ), ); } // Extend ConsumerWidget instead of StatelessWidget, which is exposed by Riverpod class MyApp extends ConsumerWidget { @override Widget build(BuildContext context, WidgetRef ref) { final String value = ref.watch(helloWorldProvider); return MaterialApp( home: Scaffold( appBar: AppBar(title: const Text('Example')), body: Center( child: Text(value), ), ), ); } } ``` -------------------------------- ### Example: Using Generator - Riverpod Class (Keep Alive) Source: https://riverpod.dev/docs/introduction/getting_started Illustrates how to use the `riverpodClassKeepAlive` generator for creating Riverpod classes that maintain their state. ```dart riverpodClassKeepAlive ``` -------------------------------- ### Install Riverpod and Dio Dependencies Source: https://riverpod.dev/docs/tutorials/first_app Terminal command to add flutter_riverpod and dio packages to the project. ```bash flutter pub add flutter_riverpod dio ``` -------------------------------- ### Define Providers for Mocking Source: https://riverpod.dev/docs/how_to/testing Examples of defining standard and generated providers that can be overridden during testing. ```dart // An eagerly initialized provider. final exampleProvider = FutureProvider((ref) async => 'Hello world'); ``` ```dart // An eagerly initialized provider. @riverpod Future example(Ref ref) async => 'Hello world'; ``` -------------------------------- ### Riverpod Generator: AutoDispose FutureProvider with Cache Duration Source: https://riverpod.dev/docs/concepts2/auto_dispose This example demonstrates using the `cacheFor` extension method with a provider generated by `riverpod_generator`. It achieves the same functionality as the previous example, keeping the `FutureProvider`'s state alive for 5 minutes. ```dart @riverpod Future example(Ref ref) async { /// Keeps the state alive for 5 minutes ref.cacheFor(const Duration(minutes: 5)); return http.get(Uri.https('example.com')); } ``` -------------------------------- ### Basic Hello World with Riverpod in Flutter Source: https://riverpod.dev/docs/introduction/getting_started A minimal Flutter application demonstrating Riverpod's basic provider setup and usage. Wrap your app in ProviderScope and use ConsumerWidget to access providers. ```dart import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; // We create a "provider", which will store a value (here "Hello world"). // By using a provider, this allows us to mock/override the value exposed. final helloWorldProvider = Provider((_) => 'Hello world'); void main() { runApp( // For widgets to be able to read providers, we need to wrap the entire // application in a "ProviderScope" widget. // This is where the state of our providers will be stored. ProviderScope( child: MyApp(), ), ); } // Extend ConsumerWidget instead of StatelessWidget, which is exposed by Riverpod class MyApp extends ConsumerWidget { @override Widget build(BuildContext context, WidgetRef ref) { final String value = ref.watch(helloWorldProvider); return MaterialApp( home: Scaffold( appBar: AppBar(title: const Text('Example')), body: Center( child: Text(value), ), ), ); } } ``` -------------------------------- ### Create Custom ProviderListenables with SyncProviderTransformerMixin Source: https://riverpod.dev/docs/whats_new Demonstrates how to create custom `ProviderListenable` objects using `SyncProviderTransformerMixin`. This example implements a `where` condition for `provider.select` that filters based on a boolean callback. ```dart final class Where with SyncProviderTransformerMixin { Where(this.source, this.where); @override final ProviderListenable source; final bool Function(T previous, T value) where; @override ProviderTransformer transform( ProviderTransformerContext context, ) { return ProviderTransformer( initState: (_) => context.sourceState.requireValue, listener: (self, previous, next) { if (where(previous, next)) self.state = next; }, ); } } extension on ProviderListenable { ProviderListenable where( bool Function(T previous, T value) where, ) => Where(this, where); } ``` -------------------------------- ### Riverpod Notifier Codegen Example Source: https://riverpod.dev/docs/from_provider/quickstart This example shows a fully migrated Notifier using Riverpod's code generation. It defines a Notifier class with an initial state and an increment method, replacing the need for temporary extensions. ```dart @riverpod class MyNotifier extends _$MyNotifier { @override int build() => 0; void increment() => state++; } ``` -------------------------------- ### Install Flutter Riverpod Snippets for VS Code Source: https://riverpod.dev/docs/introduction/getting_started For Flutter and VS Code users, install the Flutter Riverpod Snippets extension for enhanced productivity. ```plaintext Flutter Riverpod Snippets ``` -------------------------------- ### Install Riverpod Gen Shortcuts for Android Studio/IntelliJ Source: https://riverpod.dev/docs/introduction/getting_started For Flutter and Android Studio or IntelliJ users, consider installing Riverpod Gen Shortcuts or Flutter Riverpod Snippets. ```plaintext Riverpod Gen Shortcuts OR Flutter Riverpod Snippets ``` -------------------------------- ### Hello World with Riverpod and flutter_hooks Source: https://riverpod.dev/docs/introduction/getting_started This example shows how to integrate Riverpod with flutter_hooks for managing state within your Flutter widgets. Use HookConsumerWidget to leverage hooks alongside Riverpod providers. ```dart import 'package:flutter/material.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; // We create a "provider", which will store a value (here "Hello world"). // By using a provider, this allows us to mock/override the value exposed. final helloWorldProvider = Provider((_) => 'Hello world'); void main() { runApp( // For widgets to be able to read providers, we need to wrap the entire // application in a "ProviderScope" widget. // This is where the state of our providers will be stored. ProviderScope( child: MyApp(), ), ); } // Extend HookConsumerWidget instead of HookWidget, which is exposed by Riverpod class MyApp extends HookConsumerWidget { @override Widget build(BuildContext context, WidgetRef ref) { // We can use hooks inside HookConsumerWidget final counter = useState(0); final String value = ref.watch(helloWorldProvider); return MaterialApp( home: Scaffold( appBar: AppBar(title: const Text('Example')), body: Center( child: Text('$value ${counter.value}'), ), ), ); } } ``` -------------------------------- ### Offline Persistence Example Source: https://riverpod.dev/docs/whats_new Demonstrates fetching todos from a server while offline persistence is enabled. The persisted state is available during the network request, and the server state takes precedence upon completion. ```dart final todos = await fetchTodos(); return todos; } Future add(Todo todo) async { // When modifying the state, no need for any extra logic to persist the change. // Riverpod will automatically cache the new state and write it to the DB. state = AsyncData([...await future, todo]); } ``` -------------------------------- ### Synchronous, Future, and Stream Examples Source: https://riverpod.dev/docs/concepts2/providers Illustrates the basic structure of synchronous, Future, and Stream functions in Dart, which correspond to the types of data providers can handle. ```dart int synchronous() => 0; Future future() async => 0; Stream stream() => Stream.value(0); ``` -------------------------------- ### Accessing Provider Value Directly (Conceptual) Source: https://riverpod.dev/docs/concepts2/containers This conceptual example shows how providers might be accessed if they stored their own state, contrasting with Riverpod's ref.watch approach. ```dart print(helloWorldProvider.value); // Prints "Hello world!" ``` -------------------------------- ### Install Riverpod SQFlite dependencies Source: https://riverpod.dev/docs/concepts2/offline Command to add the necessary packages for SQFlite-based offline persistence in a Dart or Flutter project. ```shell dart pub add riverpod_sqflite sqflite ``` -------------------------------- ### Indirect Provider Usage with keepAlive (Riverpod Generator) Source: https://riverpod.dev/docs/whats_new This example uses `@riverpod` for both providers. `another` depends on `example`. The `MyWidget` reads `another` on button press. This demonstrates the scenario where Riverpod 3.0's improved pausing logic is beneficial. ```dart @riverpod int another(Ref ref) { ref.keepAlive(); return ref.watch(exampleProvider); } class MyWidget extends ConsumerWidget { @override Widget build(BuildContext context, WidgetRef ref) { return Button( onPressed: () { ref.read(anotherProvider); }, child: Text('Click me'), ); } } ``` -------------------------------- ### Indirect Provider Usage with Manual Pausing (Riverpod) Source: https://riverpod.dev/docs/whats_new This example shows a provider `anotherProvider` that depends on `exampleProvider`. The `MyWidget` reads `anotherProvider` on button press. In Riverpod 2.0, this scenario had issues with `exampleProvider` not pausing correctly. ```dart final anotherProvider = Provider((ref) { return ref.watch(exampleProvider); }); class MyWidget extends ConsumerWidget { @override Widget build(BuildContext context, WidgetRef ref) { return Button( onPressed: () { ref.read(anotherProvider); }, child: Text('Click me'), ); } } ``` -------------------------------- ### Riverpod: AutoDispose FutureProvider with Cache Duration Source: https://riverpod.dev/docs/concepts2/auto_dispose This example shows how to use the `cacheFor` extension method within a `FutureProvider.autoDispose`. It keeps the asynchronous data fetched by the provider alive for 5 minutes, preventing unnecessary refetches if the provider is accessed within that timeframe. ```dart final provider = FutureProvider.autoDispose((ref) async { /// Keeps the state alive for 5 minutes ref.cacheFor(const Duration(minutes: 5)); return http.get(Uri.https('example.com')); }); ``` -------------------------------- ### Initialize Flutter Project Source: https://riverpod.dev/docs/tutorials/first_app Command to create a new Flutter project via the terminal. ```bash flutter create first_app ``` -------------------------------- ### Configure Main Application Entry Source: https://riverpod.dev/docs/tutorials/first_app Sets up the MaterialApp with the HomeView widget. ```dart import 'package:flutter/material.dart'; import 'home.dart'; void main() { runApp(const MyApp()); } class MyApp extends StatelessWidget { const MyApp({super.key}); @override Widget build(BuildContext context) { return const MaterialApp(home: HomeView()); } } ``` -------------------------------- ### ProviderException Wraps Original Errors (riverpod_generator) Source: https://riverpod.dev/docs/whats_new This example demonstrates the old error-throwing behavior when using riverpod_generator. ```dart @riverpod Future example(Ref ref) async { throw StateError('Error'); } // ... ElevatedButton( onPressed: () async { // This will rethrow the StateError ref.read(exampleProvider).requireValue; // This also rethrows the StateError await ref.read(exampleProvider.future); }, child: Text('Click me'), ); ``` -------------------------------- ### Combining Providers: ProxyProvider with Stateless Objects Source: https://riverpod.dev/docs/from_provider/provider_vs_riverpod Demonstrates how to create a new provider that depends on another provider to produce a stateless object (an immutable string in this case). ```APIDOC ## Combining Providers: ProxyProvider with Stateless Objects ### Description This section explains how to combine providers in Riverpod to create a new provider that depends on another provider, similar to Flutter's `ProxyProvider` for stateless objects. ### Method `Provider` with `ref.watch` ### Endpoint N/A (Conceptual example) ### Parameters N/A ### Request Example ```dart class UserIdNotifier extends ChangeNotifier { String? userId; } final userIdNotifierProvider = ChangeNotifierProvider( (ref) => UserIdNotifier(), ); final labelProvider = Provider((ref) { UserIdNotifier userIdNotifier = ref.watch(userIdNotifierProvider); return 'The user ID of the user is ${userIdNotifier.userId}'; }); ``` ### Response #### Success Response (200) Returns a `String` that updates automatically when the dependent provider changes. #### Response Example ```dart // When userIdNotifierProvider.userId changes, labelProvider will emit the new string. // Example output: 'The user ID of the user is someUserId' ``` ``` -------------------------------- ### Add Hooks Riverpod and Flutter Hooks Dependencies Source: https://riverpod.dev/docs/introduction/getting_started Install the hooks_riverpod package along with flutter_hooks for Flutter projects. ```bash flutter pub add hooks_riverpod flutter pub add flutter_hooks ``` -------------------------------- ### Riverpod: Splitting Logic with Multiple Providers Source: https://riverpod.dev/docs/from_provider/motivation Demonstrates how Riverpod allows multiple providers of the same type by enabling the free splitting of logic into smaller, manageable pieces. ```dart final itemsProvider = Provider.autoDispose( (ref) => [], // ... ); final evenItemsProvider = Provider.autoDispose((ref) { final items = ref.watch(itemsProvider); return [...items.whereIndexed((index, element) => index.isEven)]; }); ``` ```dart @riverpod List items(Ref ref) { return []; // ... } @riverpod List evenItems(Ref ref) { final items = ref.watch(itemsProvider); return [...items.whereIndexed((index, element) => index.isEven)]; } ``` -------------------------------- ### Widget Testing with ProviderScope Source: https://riverpod.dev/docs/how_to/testing Illustrates how to set up widget tests using Riverpod by wrapping the widget tree with `ProviderScope` and obtaining a `ProviderContainer` from the test environment. ```APIDOC ## Widget Testing with ProviderScope ### Description This section covers widget testing with Riverpod, demonstrating the necessity of wrapping the widget tree with `ProviderScope` when using `tester.pumpWidget`. It also shows how to access the `ProviderContainer` via `tester.container()` for interacting with providers within widget tests. ### Method N/A (Conceptual Example) ### Endpoint N/A ### Parameters N/A ### Request Example ```dart void main() { testWidgets('Some description', (tester) async { await tester.pumpWidget( const ProviderScope(child: YourWidgetYouWantToTest()), ); final container = tester.container(); // TODO interact with your providers expect( container.read(provider), 'some value', ); }); } ``` ### Response #### Success Response (200) N/A (Conceptual Example) #### Response Example N/A ``` -------------------------------- ### Eagerly Initialize Providers with a ConsumerWidget Source: https://riverpod.dev/docs/how_to/eager_initialization Demonstrates how to create a wrapper widget that watches a provider at the application root. This ensures the provider is initialized immediately without causing the entire application to rebuild when the provider state changes. ```dart void main() { runApp(ProviderScope(child: MyApp())); } class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return const _EagerInitialization( child: MaterialApp(), ); } } class _EagerInitialization extends ConsumerWidget { const _EagerInitialization({required this.child}); final Widget child; @override Widget build(BuildContext context, WidgetRef ref) { ref.watch(myProvider); return child; } } ``` -------------------------------- ### Create Mock UI View Source: https://riverpod.dev/docs/tutorials/first_app Defines a basic HomeView widget using Scaffold and Stack to display static joke content. ```dart import 'package:flutter/material.dart'; class HomeView extends StatelessWidget { const HomeView({super.key}); @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: const Text('Random Joke Generator')), body: SizedBox.expand( child: Stack( alignment: Alignment.center, children: [ const SelectableText( 'What kind of bagel can fly?\n\n' 'A plain bagel.', textAlign: TextAlign.center, style: TextStyle(fontSize: 24), ), Positioned( bottom: 20, child: ElevatedButton( onPressed: () {}, child: const Text('Get another joke'), ), ), ], ), ), ); } } ``` -------------------------------- ### ProviderException Wraps Original Errors Source: https://riverpod.dev/docs/whats_new Before Riverpod 3.0, errors thrown by providers were rethrown directly. This example shows the old behavior with a FutureProvider. ```dart final exampleProvider = FutureProvider((ref) async { throw StateError('Error'); }); // ... ElevatedButton( onPressed: () async { // This will rethrow the StateError ref.read(exampleProvider).requireValue; // This also rethrows the StateError await ref.read(exampleProvider.future); }, child: Text('Click me'), ); ``` -------------------------------- ### Testing with ProviderContainer.test Source: https://riverpod.dev/docs/concepts2/containers Use ProviderContainer.test within tests for automatic container disposal. This simplifies test setup by managing the container's lifecycle. ```dart test('Counter starts at 0 and can be incremented', () { // No need to dispose the container when the test ends final container = ProviderContainer.test(); // Use the container to test your providers }); ``` -------------------------------- ### Using Consumer Widget Source: https://riverpod.dev/docs/from_provider/provider_vs_riverpod Granular rebuilds using the Consumer widget in both frameworks. ```APIDOC ## Using Consumer ### Description Demonstrates how to use the Consumer widget for performance optimization and reading multiple providers without ConsumerN variants. ### Implementation ```dart Consumer(builder: (context, ref, child) { final model1 = ref.watch(model1Provider); final model2 = ref.watch(model2Provider); return MyWidget(model1, model2); }); ``` ``` -------------------------------- ### Add Hooks Riverpod with Code Generation for Flutter Source: https://riverpod.dev/docs/introduction/getting_started Install hooks_riverpod, flutter_hooks, riverpod_annotation, riverpod_generator, and build_runner for Flutter projects using hooks and code generation. ```bash flutter pub add hooks_riverpod flutter pub add flutter_hooks flutter pub add riverpod_annotation flutter pub add dev:riverpod_generator flutter pub add dev:build_runner ``` -------------------------------- ### Initialize Riverpod App and Home Screen Source: https://riverpod.dev/docs/how_to/cancel Sets up the ProviderScope at the root of the application and defines a basic home screen with a FloatingActionButton to navigate to a detail page. ```dart void main() => runApp(const ProviderScope(child: MyApp())); class MyApp extends StatelessWidget { const MyApp({super.key}); @override Widget build(BuildContext context) { return MaterialApp( routes: { '/detail-page': (_) => const DetailPageView(), }, home: const ActivityView(), ); } } class ActivityView extends ConsumerWidget { const ActivityView({super.key}); @override Widget build(BuildContext context, WidgetRef ref) { return Scaffold( appBar: AppBar(title: const Text('Home screen')), body: const Center( child: Text('Click the button to open the detail page'), ), floatingActionButton: FloatingActionButton( onPressed: () => Navigator.of(context).pushNamed('/detail-page'), child: const Icon(Icons.add), ), ); } } ``` -------------------------------- ### Combining Providers Reactively Source: https://riverpod.dev/docs/from_provider/motivation Demonstrates how to combine multiple providers using ref.watch. This approach ensures reactive updates and avoids the complexities of ProxyProvider. ```dart final numberProvider = Provider.autoDispose((ref) { return Random().nextInt(10); }); final doubledProvider = Provider.autoDispose((ref) { final number = ref.watch(numberProvider); return number * 2; }); ``` ```dart @riverpod int number(Ref ref) { return Random().nextInt(10); } @riverpod int doubled(Ref ref) { final number = ref.watch(numberProvider); return number * 2; } ``` -------------------------------- ### Modifiable State Example Source: https://riverpod.dev/docs/concepts2/providers Shows a modifiable state variable in Dart. This variable can be changed from anywhere, analogous to modifiable providers that allow external state updates. ```dart // Anything can modify "state" var state = 0; ``` -------------------------------- ### Flutter Hello World with Riverpod Source: https://riverpod.dev/docs/introduction/getting_started A basic Flutter application demonstrating how to create and consume a simple string provider using Riverpod and Riverpod_annotation. ```dart import 'package:flutter/material.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:riverpod_annotation/riverpod_annotation.dart'; part 'main.g.dart'; // We create a "provider", which will store a value (here "Hello world"). // By using a provider, this allows us to mock/override the value exposed. @riverpod String helloWorld(Ref ref) { return 'Hello world'; } void main() { // For widgets to be able to read providers, we need to wrap the entire // application in a "ProviderScope" widget. // This is where the state of our providers will be stored. runApp( ProviderScope( child: MyApp(), ), ); } // Extend HookConsumerWidget instead of HookWidget, which is exposed by Riverpod class MyApp extends HookConsumerWidget { @override Widget build(BuildContext context, WidgetRef ref) { // We can use hooks inside HookConsumerWidget final counter = useState(0); final String value = ref.watch(helloWorldProvider); return MaterialApp( home: Scaffold( appBar: AppBar(title: const Text('Example')), body: Center( child: Text('$value ${counter.value}'), ), ), ); } } ``` -------------------------------- ### Dart Hello World with Riverpod Provider Source: https://riverpod.dev/docs/introduction/getting_started A simple Dart application demonstrating how to create and read a basic string provider using Riverpod's Provider API. ```dart import 'package:riverpod/riverpod.dart'; // We create a "provider", which will store a value (here "Hello world"). // By using a provider, this allows us to mock/override the value exposed. final helloWorldProvider = Provider((_) => 'Hello world'); void main() { // This object is where the state of our providers will be stored. final container = ProviderContainer(); // Thanks to "container", we can read our provider. final value = container.read(helloWorldProvider); print(value); // Hello world } ``` -------------------------------- ### Independent Family Provider States Source: https://riverpod.dev/docs/concepts2/family Multiple calls to the same family provider with different parameters create independent states. This example shows how `user1` and `user2` are distinct and do not affect each other. ```dart class Example extends ConsumerWidget { @override Widget build(BuildContext context, WidgetRef ref) { final user1 = ref.watch(userProvider('123')); final user2 = ref.watch(userProvider('456')); // user1 and user2 are independent. } } ``` -------------------------------- ### Await Persistence Decoding Source: https://riverpod.dev/docs/concepts2/offline Explains how to await the persistence process to initialize a provider with cached data before proceeding with other logic. ```dart @override Future> build() async { await persist( ref.watch(storageProvider.future), ).future; return state.value ?? []; } ``` -------------------------------- ### Unmodifiable State Example Source: https://riverpod.dev/docs/concepts2/providers Demonstrates an unmodifiable state variable within a Dart class. The internal state can be modified, but it cannot be changed from outside the class, similar to unmodifiable providers. ```dart // _state is internally modifiable // but cannot be modified externally var _state = 0; int get state => _state; ``` -------------------------------- ### Dart Hello World with Riverpod Generator Source: https://riverpod.dev/docs/introduction/getting_started A Dart application demonstrating how to create and read a simple string provider using Riverpod's annotation-based generator. ```dart import 'package:riverpod_annotation/riverpod_annotation.dart'; part 'main.g.dart'; // We create a "provider", which will store a value (here "Hello world"). // By using a provider, this allows us to mock/override the value exposed. @riverpod String helloWorld(Ref ref) { return 'Hello world'; } void main() { // This object is where the state of our providers will be stored. final container = ProviderContainer(); // Thanks to "container", we can read our provider. final value = container.read(helloWorldProvider); print(value); // Hello world } ``` -------------------------------- ### Riverpod Generator for FutureProvider Source: https://riverpod.dev/docs/concepts2/providers An example using Riverpod's code generator to create a FutureProvider. This approach simplifies provider declaration and offers similar caching benefits. ```dart @riverpod Future user(Ref ref) async { final response = await http.get('https://api.example.com/user/123'); return User.fromJson(response.body); } ``` -------------------------------- ### Initialize SQFlite Storage Provider Source: https://riverpod.dev/docs/concepts2/offline Demonstrates how to create a Storage instance using JsonSqFliteStorage for both standard Riverpod providers and code-generated providers. This instance should be shared across the application to manage database connections. ```dart final storageProvider = FutureProvider>((ref) async { return JsonSqFliteStorage.open( join(await getDatabasesPath(), 'riverpod.db'), ); }); ``` ```dart @riverpod Future> storage(Ref ref) async { return JsonSqFliteStorage.open( join(await getDatabasesPath(), 'riverpod.db'), ); } ``` -------------------------------- ### Custom updateShouldNotify for StreamNotifier Source: https://riverpod.dev/docs/whats_new Starting Riverpod 3.0, all providers use `==` for `updateShouldNotify`. If this change impacts your listeners, you can override `updateShouldNotify` with a custom implementation, as shown for `StreamNotifier`. ```dart class TodoList extends StreamNotifier { @override Stream build() => Stream(...); @override bool updateShouldNotify(AsyncValue previous, AsyncValue next) { // Custom implementation return true; } } ``` -------------------------------- ### Get New State After Reset with Ref.read Source: https://riverpod.dev/docs/concepts2/refs After invalidating a provider, you can immediately obtain its new state by calling Ref.read. This is useful when you need the updated value right after the reset. ```dart ref.invalidate(tickProvider); final newTick = ref.read(tickProvider); ``` -------------------------------- ### Creating Parameterized Providers with Family and AutoDispose Source: https://riverpod.dev/docs/from_provider/provider_vs_riverpod Shows how to define providers that accept parameters to create unique states per input, using both standard provider syntax and the Riverpod generator. ```dart class ParamsType extends Equatable { const ParamsType({required this.seed, required this.max}); final int seed; final int max; @override List get props => [seed, max]; } final randomProvider = Provider.family.autoDispose((ref, params) { return Random(params.seed).nextInt(params.max); }); ``` ```dart @riverpod int random(Ref ref, {required int seed, required int max}) { return Random(seed).nextInt(max); } ``` -------------------------------- ### Run Riverpod Migration Tool Source: https://riverpod.dev/docs/migration/0.13.0_to_0.14.0 Command to execute the Riverpod migration tool within a project directory. This tool analyzes the project and suggests code changes for the new syntax. ```bash riverpod migrate ``` -------------------------------- ### Enable riverpod_lint in analysis_options.yaml Source: https://riverpod.dev/docs/introduction/getting_started Add this to your analysis_options.yaml to enable riverpod_lint for better code quality and custom refactoring options. Ensure you replace with the actual latest version from pub.dev. ```yaml plugins: riverpod_lint: ``` -------------------------------- ### Auto-dispose Provider with Async Gap (Riverpod Generator) Source: https://riverpod.dev/docs/whats_new This example uses riverpod_generator to define providers and illustrates the same issue as the previous snippet, where an auto-dispose provider is prematurely disposed during an async gap. ```dart @riverpod Stream autoDispose(Ref ref) { ref.onDispose(() => print('disposed')); ref.onCancel(() => print('paused')); ref.onResume(() => print('resumed')); // A stream that emits a value every second return Stream.periodic(Duration(seconds: 1), (i) => i); } @riverpod Future asynchronousExample(Ref ref) async { print('Before async gap'); // An async gap inside a provider ; typically an API call. // This will dispose the "autoDispose" provider // before the async operation is completed await null; print('after async gap'); // We listen to our auto-dispose provider // after the async operation return ref.watch(autoDisposeProvider.future); } void main() { final container = ProviderContainer(); // This will print 'disposed' every second, // and will constantly print 0 container.listen(asynchronousExampleProvider, (_, value) { if (value is AsyncData) print('${value.value}\n----'); }); } ``` -------------------------------- ### AsyncNotifier Migration Templates Source: https://riverpod.dev/docs/migration/from_change_notifier Templates for migrating to AsyncNotifier. Includes both the manual class-based provider definition and the recommended @riverpod code-generation approach. ```dart class MyNotifier extends AsyncNotifier> { @override FutureOr> build() { return []; } Future addTodo(Todo todo) async { } } final myNotifierProvider = AsyncNotifierProvider.autoDispose>(MyNotifier.new); ``` ```dart @riverpod class MyNotifier extends _$MyNotifier { @override FutureOr> build() { return []; } Future addTodo(Todo todo) async { } } ``` -------------------------------- ### Implementing Lifecycle Callbacks in Riverpod Source: https://riverpod.dev/docs/from_provider/provider_vs_riverpod Demonstrates how to use onCancel and onDispose within a provider to handle state cleanup when the provider is no longer in use. ```dart ref.onCancel((){ print("No one listens to me anymore!"); }); ref.onDispose((){ print("If I've been defined as `.autoDispose`, I just got disposed!"); }); ``` -------------------------------- ### Legacy ChangeNotifier Implementation Source: https://riverpod.dev/docs/migration/from_change_notifier An example of a ChangeNotifier implementation that manually manages loading, error, and data states. This approach is prone to bugs due to manual notifyListeners calls and complex try-catch-finally blocks. ```dart class MyChangeNotifier extends ChangeNotifier { MyChangeNotifier() { _init(); } List todos = []; bool isLoading = true; bool hasError = false; Future _init() async { try { final json = await http.get('api/todos'); todos = [...json.map(Todo.fromJson)]; } on Exception { hasError = true; } finally { isLoading = false; notifyListeners(); } } Future addTodo(int id) async { isLoading = true; notifyListeners(); try { final json = await http.post('api/todos'); todos = [...json.map(Todo.fromJson)]; hasError = false; } on Exception { hasError = true; } finally { isLoading = false; notifyListeners(); } } } final myChangeProvider = ChangeNotifierProvider((ref) { return MyChangeNotifier(); }); ``` -------------------------------- ### Create a Family Provider (Generated) Source: https://riverpod.dev/docs/concepts2/family When using code generation, family providers can accept any number of parameters directly in their function signature. This example shows a generated FutureProvider accepting a String id. ```dart @riverpod Future user( Ref ref, String id, ) async { final dio = Dio(); final response = await dio.get('https://api.example.com/users/$id'); return User.fromJson(response.data); } ``` -------------------------------- ### Combining Providers: ProxyProvider with Stateful Objects Source: https://riverpod.dev/docs/from_provider/provider_vs_riverpod Illustrates how to combine providers in Riverpod to expose stateful objects, using `ChangeNotifierProvider` and `ref.listen` to manage updates. ```APIDOC ## Combining Providers: ProxyProvider with Stateful Objects ### Description This section explains how to combine providers in Riverpod to expose stateful objects, such as `ChangeNotifier` instances, using `ChangeNotifierProvider` and `ref.listen`. ### Method `ChangeNotifierProvider` with `ref.listen` ### Endpoint N/A (Conceptual example) ### Parameters N/A ### Request Example ```dart class UserIdNotifier extends ChangeNotifier { String? userId; } final userIdNotifierProvider = ChangeNotifierProvider( (ref) => UserIdNotifier(), ); class UserNotifier extends ChangeNotifier { String? _userId; void setUserId(String? userId) { if (userId != _userId) { print('The user ID changed from $_userId to $userId'); _userId = userId; } } } final userNotifierProvider = ChangeNotifierProvider((ref) { final userNotifier = UserNotifier(); ref.listen( userIdNotifierProvider, (previous, next) { if (previous?.userId != next.userId) { userNotifier.setUserId(next.userId); } }, ); return userNotifier; }); ``` ### Response #### Success Response (200) Returns a `ChangeNotifier` instance that updates its internal state based on changes in a dependent provider. #### Response Example ```dart // When userIdNotifierProvider.userId changes, UserNotifier.setUserId is called. // Console output example: 'The user ID changed from null to someUserId' ``` ``` -------------------------------- ### Listen to Provider Disposal with Ref.onDispose (Riverpod Generator) Source: https://riverpod.dev/docs/concepts2/refs Register a callback using ref.onDispose to execute code when a provider is disposed. This is useful for cleanup operations, similar to the dispose method in Flutter widgets. This example uses the riverpod_generator API. ```dart @riverpod int counter(Ref ref) { ref.onDispose(() { // This is called when the provider is disposed print('Counter provider is being disposed'); }); return 0; } ``` -------------------------------- ### Initialize ProviderContainer for Unit Testing Source: https://riverpod.dev/docs/how_to/testing Demonstrates how to create a ProviderContainer for unit tests. It is crucial to create a new container for each test to ensure state isolation. ```dart void main() { test('Some description', () { final container = ProviderContainer.test(); expect( container.read(provider), equals('some value'), ); }); } ``` -------------------------------- ### Implement Detail Page with FutureProvider Source: https://riverpod.dev/docs/how_to/cancel Defines an Activity model and a FutureProvider to fetch data from an API, with a UI that handles loading, error, and success states using RefreshIndicator. ```dart class Activity { Activity({required this.activity, required this.type, required this.participants, required this.price}); factory Activity.fromJson(Map json) { return Activity( activity: json['activity']! as String, type: json['type']! as String, participants: json['participants']! as int, price: json['price']! as double, ); } final String activity; final String type; final int participants; final double price; } final activityProvider = FutureProvider.autoDispose((ref) async { final response = await http.get(Uri.https('www.boredapi.com', '/api/activity')); final json = jsonDecode(response.body) as Map; return Activity.fromJson(json); }); class DetailPageView extends ConsumerWidget { const DetailPageView({super.key}); @override Widget build(BuildContext context, WidgetRef ref) { final activity = ref.watch(activityProvider); return Scaffold( appBar: AppBar(title: const Text('Detail page')), body: RefreshIndicator( onRefresh: () => ref.refresh(activityProvider.future), child: ListView( children: [ switch (activity) { AsyncValue(:final value?) => Text(value.activity), AsyncValue(:final error?) => Text('Error: $error'), _ => const Center(child: CircularProgressIndicator()), }, ], ), ), ); } } ``` -------------------------------- ### Listen to Provider Disposal with Ref.onDispose (Provider) Source: https://riverpod.dev/docs/concepts2/refs Register a callback using ref.onDispose to execute code when a provider is disposed. This is useful for cleanup operations, similar to the dispose method in Flutter widgets. This example uses the standard Provider API. ```dart final counterProvider = Provider((ref) { ref.onDispose(() { // This is called when the provider is disposed print('Counter provider is being disposed'); }); return 0; }); ``` -------------------------------- ### Testing Notifiers with ProviderContainer Source: https://riverpod.dev/docs/migration/from_state_notifier Illustrates the recommended way to test Notifiers by obtaining the instance through a ProviderContainer rather than manual instantiation, ensuring proper lifecycle management. ```dart void main(List args) { test('my test', () { final container = ProviderContainer(); addTearDown(container.dispose); final Notifier notifier = container.read(myNotifierProvider.notifier); final int state = container.read(myNotifierProvider); }); } ``` -------------------------------- ### Flutter App with Riverpod Annotations and Freezed Source: https://riverpod.dev/docs/how_to/pull_to_refresh This snippet presents an enhanced Flutter application using Riverpod with code generation (`riverpod_annotation`) and data modeling with Freezed. It achieves the same functionality as the previous example but with more concise provider definitions and immutable data classes generated automatically. This approach reduces boilerplate code and improves maintainability. ```dart import 'dart:convert'; import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:freezed_annotation/freezed_annotation.dart'; import 'package:http/http.dart' as http; import 'package:riverpod_annotation/riverpod_annotation.dart'; part 'codegen.g.dart'; part 'codegen.freezed.dart'; void main() => runApp(ProviderScope(child: MyApp())); class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp(home: ActivityView()); } } class ActivityView extends ConsumerWidget { @override Widget build(BuildContext context, WidgetRef ref) { final activity = ref.watch(activityProvider); return Scaffold( appBar: AppBar(title: const Text('Pull to refresh')), body: RefreshIndicator( onRefresh: () => ref.refresh(activityProvider.future), child: ListView( children: [ switch (activity) { AsyncValue(:final value?) => Text(value.activity), AsyncValue(:final error?) => Text('Error: $error'), _ => const CircularProgressIndicator(), }, ], ), ), ); } } @riverpod Future activity(Ref ref) async { final response = await http.get( Uri.https('www.boredapi.com', '/api/activity'), ); final json = jsonDecode(response.body) as Map; return Activity.fromJson(Map.from(json)); } @freezed sealed class Activity with _$Activity { factory Activity({ required String activity, required String type, required int participants, required double price, }) = _Activity; factory Activity.fromJson(Map json) => _$ActivityFromJson(json); } ```