maybeWhen()
maybeWhen() is an AsyncValue method that lets you handle only the asynchronous states you care about while providing a fallback for all other states.
What is it?
maybeWhen() is a more flexible version of when().
Unlike when(), which requires callbacks for all three states, maybeWhen() allows you to specify callbacks for only the states you want to handle.
Any unhandled state is automatically passed to the orElse callback.
This makes maybeWhen() useful when you only need to customize one or two states.
Why does it exist?
Sometimes you don't need to handle every possible state.
For example:
- Show a loading indicator only.
- Handle errors specially.
- Display cached data for all non-loading states.
- Perform logic only when data is available.
Using when() in these situations forces you to write unnecessary callbacks.
maybeWhen() keeps the code concise.
Syntax
user.maybeWhen(
data: (user) {
return Text(user.name);
},
orElse: () {
return const SizedBox();
},
);
Explanation:
- The
datacallback runs only when the state isAsyncData. - Every other state executes
orElse.
Parameters
| Parameter | Required | Description |
|---|---|---|
loading |
❌ | Handles the loading state |
data |
❌ | Handles the data state |
error |
❌ | Handles the error state |
orElse |
✅ | Handles every unhandled state |
Unlike when(), only orElse is mandatory.
Execution Flow
AsyncValue
│
┌────────┼────────┐
│ │ │
▼ ▼ ▼
Loading Data Error
│ │ │
│ ▼ │
│ data() │
│ │
└──────┬──────────┘
▼
orElse()
Only the callbacks you provide are executed. Every other state falls back to orElse.
Mental Model
Think of maybeWhen() as a selective filter.
AsyncValue
│
▼
Is it Data?
│
┌───┴───┐
│ │
Yes No
│ │
▼ ▼
data() orElse()
Instead of handling every state, you only focus on the one(s) you care about.
Examples
Handle Only Data
return user.maybeWhen(
data: (user) {
return Text(user.name);
},
orElse: () {
return const CircularProgressIndicator();
},
);
Explanation:
- Displays the user's name when data is available.
- All other states show a loading indicator.
Handle Only Errors
return user.maybeWhen(
error: (error, stackTrace) {
return ErrorView(error);
},
orElse: () {
return const SizedBox();
},
);
Explanation:
- Only customizes the error state.
- Loading and data share the default UI.
Handle Loading Only
return user.maybeWhen(
loading: () {
return const CircularProgressIndicator();
},
orElse: () {
return const UserScreen();
},
);
Explanation:
- Shows a spinner while loading.
- Uses the same UI for data and error.
Real-World Example
final profile = ref.watch(profileProvider);
return profile.maybeWhen(
error: (error, stackTrace) {
return RetryScreen(
message: 'Unable to load profile.',
);
},
orElse: () {
return const ProfileContent();
},
);
Explanation:
- Only the error state receives special treatment.
- Every other state uses the default content.
When to Use
Use maybeWhen() when:
- You only care about one or two states.
- Most states share the same UI.
- You want a default fallback.
- You're writing concise conditional UI.
When NOT to Use
Avoid maybeWhen() when:
- Every state requires different behavior.
- You need exhaustive handling.
- You're building complete loading/data/error UIs.
In these cases, prefer when().
Best Practices
- Always provide a meaningful
orElse. - Use
when()when handling all states. - Keep callbacks lightweight.
- Avoid putting business logic inside callbacks.
- Prefer
maybeWhen()only when it simplifies the code.
Common Mistakes
1. Forgetting orElse
❌ Wrong
user.maybeWhen(
data: (user) {
return Text(user.name);
},
);
Why it's wrong:
orElseis required.- Riverpod needs a fallback for unhandled states.
✔ Correct
user.maybeWhen(
data: (user) {
return Text(user.name);
},
orElse: () {
return const SizedBox();
},
);
2. Using maybeWhen() for Every State
❌ Wrong
user.maybeWhen(
loading: LoadingView.new,
data: UserView.new,
error: ErrorView.new,
orElse: SizedBox.new,
);
Why it's wrong:
- All states are already handled.
when()is simpler and more expressive.
✔ Correct
user.when(
loading: LoadingView.new,
data: UserView.new,
error: ErrorView.new,
);
3. Ignoring Important States
❌ Wrong
user.maybeWhen(
data: UserView.new,
orElse: SizedBox.new,
);
Why it's wrong:
- Errors are silently ignored.
- Users receive no feedback.
✔ Correct
Handle errors when they matter to the user.
4. Returning Different Types
❌ Wrong
data: (user) => Text(user.name),
orElse: () => 'Loading',
Why it's wrong:
- All callbacks must return the same type.
✔ Correct
Return a Widget (or another consistent type) from every callback.
maybeWhen() vs when()
| Feature | maybeWhen() |
when() |
|---|---|---|
| Handles all states | ❌ | ✅ |
orElse required |
✅ | ❌ |
| Optional callbacks | ✅ | ❌ |
| Exhaustive | ❌ | ✅ |
| Best for partial handling | ✅ | ❌ |
| Recommended for full UI | ❌ | ✅ |
Related APIs
when()map()maybeMap()AsyncValueAsyncLoadingAsyncDataAsyncError
Summary
maybeWhen() allows you to handle only the asynchronous states you care about while providing a default orElse callback for every other state. It is ideal when one or two states need special handling, but for complete loading, data, and error UIs, when() remains the recommended and more expressive choice.