Module 1
Topic 10

AsyncValue

Handling loading, error, and data states elegantly in Riverpod with type-safe pattern matching.

Riverpod – AsyncValue flutter_riverpod package
What Is AsyncValue?

AsyncValue is a sealed class in Riverpod that represents the state of an asynchronous operation. It elegantly wraps the three possible states of a Future or Stream :

Loading
The operation is in progress
Error
The operation failed with an error
Data
The operation completed with data

✅ Why AsyncValue?

AsyncValue provides a type-safe way to handle asynchronous states. Instead of using null checks or custom state classes, you get a unified API that guarantees you handle all three states.

The Three States of AsyncValue

AsyncValue can be in one of three states. Each state provides different properties:

Handling AsyncValue States

Riverpod provides several ways to handle AsyncValue states. The most common is the .when() method.

💡 Which Method to Use?

  • Use .when() when you need to handle all three states
  • Use .maybeWhen() when you have a fallback for unhandled states
  • Use .whenOrNull() when you only care about the data state
  • Use conditionals when you need more complex logic
Complete Example: User Profile

Here's a complete example showing how to use AsyncValue to display a user profile with loading, error, and data states.

Step-by-Step Explanation
1.
Define the Provider userProvider is a FutureProvider that returns an AsyncValue .
2.
Watch the Provider ref.watch(userProvider) gives you the AsyncValue object.
3.
Use .when() – The .when() method handles all three states: loading shows a spinner, error shows an error message with retry, and data displays the user profile.
4.
Refresh – The ref.refresh(userProvider) triggers a new fetch and resets the state to loading.
Advanced AsyncValue Usage

AsyncValue offers several advanced methods for common operations:

AsyncValue vs Manual State Management

AsyncValue (Riverpod)

  • Type-safe pattern matching
  • Built-in loading state
  • Built-in error state
  • Automatic caching
  • Less boilerplate code
  • Forces handling all states

Manual State Class

  • Manual null checks
  • Custom loading boolean
  • Custom error field
  • Manual caching logic
  • More boilerplate
  • Can forget to handle states
Common Mistakes
❌ Mistake 1: Not handling all states

Forgetting to handle the loading or error state can lead to a poor user experience or crashes. Always handle all three states.

✅ Correct: Always handle loading, error, and data states

Use .when() to ensure all three states are handled explicitly.

❌ Mistake 2: Using .value directly without checking

asyncValue.value can be null if the state is loading or error. Always check hasValue first.

✅ Correct: Use .when() or check .hasValue

Use .when() to access the data safely, or check hasValue before using .value .

❌ Mistake 3: Not resetting error state

After an error occurs, the error state persists until the next successful operation. Make sure to handle retries properly.

✅ Correct: Provide retry mechanism

In the error state, provide a button that calls ref.refresh() to retry the operation.

AsyncValue with StreamProvider

AsyncValue works the same way with StreamProvider . The main difference is that the data state updates multiple times as the stream emits new values.

Refreshing AsyncValue

When you want to refetch data, use ref.refresh() or ref.invalidate() .

🎯 Key Takeaway

AsyncValue is the standard way to handle asynchronous states in Riverpod. It provides a type-safe, elegant API for loading, error, and data states. Always use .when() to handle all three states , and use ref.refresh() to retry failed operations. With AsyncValue, you'll never forget to handle a state again.