ref.refresh()
ref.refresh() immediately invalidates a provider, recreates it, and returns its new value in a single operation.
What is it?
ref.refresh() is used to force a provider to recompute immediately.
Unlike ref.invalidate(), which only marks a provider as invalid, ref.refresh():
- Invalidates the provider.
- Immediately recreates it.
- Returns the newly computed value.
Think of it as a shortcut for:
ref.invalidate(provider);
ref.read(provider);
except it happens atomically and is handled internally by Riverpod.
Why does it exist?
Sometimes waiting until the next access isn't desirable.
For example:
- A user performs pull-to-refresh.
- Data must be fetched immediately.
- A retry button is pressed.
- Cached information should be replaced right now.
Using ref.invalidate() would only clear the provider's state.
ref.refresh() ensures the provider is recreated immediately, making it ideal for user-initiated refresh operations.
Syntax
Refreshing a Provider
final user = ref.refresh(userProvider);
Explanation:
- Discards the current provider state.
- Rebuilds the provider immediately.
- Returns the newly computed value.
Refreshing an Async Provider
final user = ref.refresh(userProvider);
Explanation:
- Returns a new
AsyncValue<User>. - The provider begins loading immediately.
Pull to Refresh
RefreshIndicator(
onRefresh: () async {
ref.refresh(productsProvider);
},
child: ProductList(),
)
Explanation:
- User pulls down.
- Products provider is recreated immediately.
Return Value
Unlike ref.invalidate(), ref.refresh() returns the provider's new value.
Examples:
| Provider Type | Return Value |
|---|---|
Provider<int> |
int |
Provider<String> |
String |
NotifierProvider<Counter, int> |
int |
FutureProvider<User> |
AsyncValue<User> |
AsyncNotifierProvider<UserNotifier, User> |
AsyncValue<User> |
StreamProvider<Message> |
AsyncValue<Message> |
The returned value is the same type that ref.watch() or ref.read() would return.
Execution Flow
Provider has state
│
▼
ref.refresh(provider)
│
▼
Current state discarded
│
▼
build() executes immediately
│
▼
New state created
│
▼
New value returned
Unlike invalidate(), recomputation happens immediately.
Mental Model
Think of ref.refresh() as restarting a provider instantly.
Current Provider
│
▼
refresh()
│
▼
Old State Removed
│
▼
New Provider Created
│
▼
Fresh Value Returned
Instead of waiting for the next access, the provider is recreated immediately.
Examples
Refresh Cached Data
ref.refresh(productsProvider);
Explanation:
- Removes cached products.
- Fetches fresh products immediately.
Retry After an Error
ElevatedButton(
onPressed: () {
ref.refresh(userProvider);
},
child: const Text('Retry'),
)
Explanation:
- Recreates the provider.
- Starts the request again.
Pull-to-Refresh
RefreshIndicator(
onRefresh: () async {
ref.refresh(newsProvider);
},
child: const NewsList(),
)
Explanation:
- User requests fresh data.
- Provider begins loading immediately.
Real-World Example
Future<void> refreshProfile() async {
ref.refresh(profileProvider);
}
Explanation:
- Clears cached profile.
- Immediately requests the latest profile from the server.
When to Use
Use ref.refresh() when:
- Implementing pull-to-refresh.
- Retrying failed API requests.
- Refreshing cached data immediately.
- User explicitly requests fresh data.
- Immediate recomputation is required.
When NOT to Use
Avoid ref.refresh() when:
- Updating a small piece of state.
- Waiting until the next access is acceptable.
- The provider doesn't need to restart.
Instead:
- Update
state. - Use
ref.invalidate()if immediate recomputation isn't necessary.
Best Practices
- Use
refresh()for user-initiated refresh actions. - Keep refresh logic inside notifiers or UI events.
- Avoid repeatedly refreshing providers in short intervals.
- Prefer updating
statefor simple state changes. - Refresh only the providers that actually need new data.
Common Mistakes
1. Using refresh() for Normal State Updates
❌ Wrong
void increment() {
ref.refresh(counterProvider);
}
Why it's wrong:
- The provider is recreated unnecessarily.
✔ Correct
void increment() {
state++;
}
2. Using invalidate() When Immediate Data Is Needed
❌ Wrong
ref.invalidate(productsProvider);
Why it's wrong:
- The provider won't rebuild until it is accessed again.
✔ Correct
ref.refresh(productsProvider);
3. Refreshing Multiple Providers Unnecessarily
❌ Wrong
ref.refresh(userProvider);
ref.refresh(cartProvider);
ref.refresh(settingsProvider);
ref.refresh(productsProvider);
Why it's wrong:
- Causes unnecessary recomputation.
- May result in multiple network requests.
✔ Correct
Refresh only the providers that need updated data.
4. Expecting refresh() to Update Other Providers
❌ Wrong
ref.refresh(userProvider);
// Expecting cartProvider to refresh too
Why it's wrong:
- Only the specified provider is refreshed.
✔ Correct
Refresh each provider explicitly or design provider dependencies so dependent providers rebuild automatically.
ref.refresh() vs ref.invalidate()
| Feature | ref.refresh() |
ref.invalidate() |
|---|---|---|
| Clears provider state | ✅ | ✅ |
| Immediately recreates provider | ✅ | ❌ |
| Returns new provider value | ✅ | ❌ |
| Waits until next access | ❌ | ✅ |
| Best for pull-to-refresh | ✅ | ❌ |
Related APIs
ref.invalidate()ref.invalidateSelf()ref.watch()ref.read()build()
Summary
ref.refresh() immediately discards a provider's current state, recreates it, and returns the new value. It is the preferred API for pull-to-refresh, retry actions, and any scenario where fresh state is required immediately. Unlike ref.invalidate(), which waits until the next access, ref.refresh() performs the entire refresh process in a single operation.