Riverpod Documentation

repository·master·Indexed 27 days ago

https://github.com/rrousselgit/riverpod

Riverpod is a reactive caching and data-binding framework for Dart and Flutter that simplifies asynchronous state management by separating business logic from the UI. The ecosystem includes riverpod_generator and riverpod_annotation for automated provider creation via the @riverpod annotation, as well as riverpod_lint, an analysis server plugin that provides warnings and quick fixes to prevent common state management issues.

Tokens
37.9K
Snippets
120
Records
237
Agent score
92%

What's inside Riverpod

  1. Overview of Riverpod

    master

    Riverpod is a reactive caching and data-binding framework designed to make working with asynchronous code easier. It helps separate logic from UI, ensures code is testable and scalable, and handles loading/error states by default.

    Key packages include:

    • riverpod: The core framework.
    • flutter_riverpod: Integration for Flutter applications.
    • hooks_riverpod: Integration for Flutter projects using flutter_hooks.
  2. Overview of riverpod_lint

    master

    riverpod_lint is a developer tool for Riverpod users designed to prevent common issues and simplify repetitive tasks. It provides warnings with quick fixes and refactoring options, such as:

    • Warning if runApp lacks a ProviderScope at its root.
    • Warning if provider parameters violate family rules.
    • Refactoring widgets to ConsumerWidget or ConsumerStatefulWidget automatically.
  3. Understand the relationship between Hooks and Riverpod

    master

    Hooks are provided by the flutter_hooks package and are used for managing local widget state (e.g., TextEditingController, AnimationController). In contrast, Riverpod providers are used for global application state. While they are separate packages, they are frequently used together.

    Recommendation: If you are new to Riverpod, avoid using hooks until you are comfortable with the core concepts. Hooks are a tradeoff: they improve code reusability and composability but introduce a new concept that can be confusing in a Flutter/Dart context.

  4. Improved async gap handling during provider rebuilds

    master

    In Riverpod 3.0, when a provider rebuilds, its previous subscriptions are not immediately removed; instead, they are paused until the rebuild completes.

    This fixes a common issue in 2.0 where an asynchronous provider watching an autoDispose provider would trigger an unexpected disposal during an await gap, causing the provider to restart or fail repeatedly. In 3.0, the autoDispose provider is kept in a paused state during the async gap, allowing the rebuild to complete smoothly.

  5. Automatic pausing of dependent providers

    master
    In Riverpod 3.0, if a provider is only used by other providers that are currently paused, the dependency will also be paused. This ensures that resource-heavy providers are not kept active if their only consumers are currently inactive (e.g., in a non-visible route).
  6. Understand the concept of Providers

    master

    Providers are memoized functions that act as wrappers around logic (like network requests). They cache the returned value so that multiple widgets can access the same data without re-executing the underlying function.

    Key features include:

    • Cache Invalidation: Using Ref.watch to combine caches and automatically invalidate dependencies.
    • Auto-disposal: Automatically releasing resources when no longer needed.
    • Data-binding: Eliminating the need for FutureBuilder or StreamBuilder.
    • Error Handling: Automatic error catching and exposure to the UI.
    • Mocking: Support for overriding providers during testing.
    • Persistence: Ability to persist results to disk.
    • Side-effect management: Built-in ways to handle loading/error states for mutations (e.g., form submissions).
  7. Configure global retry logic

    master

    To set a retry policy for all providers in your application, pass a retry function to your ProviderContainer (for pure Dart) or ProviderScope (for Flutter).

    // For pure Dart code
    final container = ProviderContainer(
      retry: myRetry,
    );
    
    // For Flutter code
    runApp(
      ProviderScope(
        retry: myRetry,
        child: MyApp(),
      ),
    );
  8. Decide whether to use Riverpod code generation

    master

    Code generation in Riverpod is optional. It is recommended only if your project is already using code generation tools like Freezed or json_serializable.

    Benefits of code generation:

    • Simplified Syntax: You don't need to manually select the provider type; Riverpod infers it from your logic.
    • Improved Readability: Providers are defined as standard functions or classes rather than "dirty global variables."
    • Flexible Parameters: You can pass any number of parameters (named, optional, or with default values) to a provider without using the .family modifier.
    • Stateful Hot-Reload: Better support for hot-reloading the code written in Riverpod.
    • Better Debugging: Generates extra metadata for the debugger.
  9. Enable or disable automatic disposal

    master

    In Riverpod, automatic disposal destroys provider resources when they are no longer used.

    • Using Code Generation: Automatic disposal is enabled by default. To opt-out (keep the state alive), set keepAlive: true in the @Riverpod annotation.
    • Without Code Generation: You must explicitly opt-in by setting isAutoDispose: true when creating the provider.

    Caution: It is highly recommended to enable automatic disposal for providers that receive parameters (families) to prevent memory leaks caused by accumulating state for every parameter combination.

    // Disable automatic disposal using code-generation
    @Riverpod(keepAlive: true)
    String helloWorld(Ref ref) => 'Hello world!';
    // Opt-in to automatic disposal without code-generation
    final helloWorldProvider = Provider<String>(
      isAutoDispose: true,
      (ref) => 'Hello world!',
    );
  10. Select asynchronous properties using selectAsync

    master

    When a provider depends on an asynchronous provider, using ref.watch(anotherProvider.future) prevents you from using the standard select method, because select operates on an AsyncValue rather than the underlying data.

    To perform a selection on the data emitted by an asynchronous provider, use selectAsync. This method works similarly to select but returns a Future that resolves to the selected value, allowing you to await the specific property you need.