WidgetRef
The object that provides access to Riverpod providers inside Flutter widgets.
What is it?
WidgetRef is the core object that connects Flutter widgets to Riverpod.
It is passed into:
ConsumerWidgetConsumerStateConsumer
It allows widgets to read, watch, and listen to providers.
Without WidgetRef, a widget cannot interact with Riverpod.
Why does it exist?
Flutter widgets do not have built-in access to external state systems.
Riverpod introduces WidgetRef to:
- Bridge Flutter UI and Riverpod container
- Provide a unified API for provider access
- Enable reactive updates (
watch) - Support one-time reads (
read) - Enable event listening (
listen)
Before WidgetRef, provider access was tightly coupled with widget wrappers and less structured patterns.
Syntax
In ConsumerWidget
class MyWidget extends ConsumerWidget {
@override
Widget build(BuildContext context, WidgetRef ref) {
final value = ref.watch(myProvider);
return Text('$value');
}
}
Explanation:
refis injected intobuild- Used to access providers directly
- Automatically rebuilds when watched providers change
In ConsumerState
class _MyState extends ConsumerState<MyWidget> {
@override
Widget build(BuildContext context) {
final value = ref.watch(myProvider);
return Text('$value');
}
}
Explanation:
refis available inside state class- Same API as ConsumerWidget
- Works with lifecycle methods
ref.watch()
final count = ref.watch(counterProvider);
Explanation:
- Subscribes to provider
- Rebuilds widget when value changes
ref.read()
final value = ref.read(counterProvider);
Explanation:
- Gets value once
- Does NOT rebuild widget
- Used for actions or one-time access
ref.listen()
ref.listen(counterProvider, (previous, next) {
print('Counter changed: $next');
});
Explanation:
- Listens to changes without rebuilding UI
- Used for side effects (snackbars, navigation, logging)
Mental Model
Think of WidgetRef as the control panel for Riverpod inside a widget.
Widget
│
▼
WidgetRef
├── watch → reactive UI updates
├── read → one-time access
└── listen → side effects
It is the only gateway between UI and providers.
Examples
Simple Usage
final messageProvider = Provider<String>((ref) {
return 'Hello Riverpod';
});
class MessageView extends ConsumerWidget {
@override
Widget build(BuildContext context, WidgetRef ref) {
final message = ref.watch(messageProvider);
return Text(message);
}
}
Explanation:
- Widget reacts automatically to provider changes
- Clean separation of UI and state
Real-World Example
final authProvider = NotifierProvider<AuthNotifier, AuthState>(
AuthNotifier.new,
);
class LoginButton extends ConsumerWidget {
@override
Widget build(BuildContext context, WidgetRef ref) {
final isLoading = ref.watch(authProvider).isLoading;
return ElevatedButton(
onPressed: isLoading
? null
: () {
ref.read(authProvider.notifier).login();
},
child: Text(isLoading ? 'Loading...' : 'Login'),
);
}
}
Explanation:
watchfor UI statereadfor actions- Clear separation of concerns
Side Effect Example
ref.listen(authProvider, (prev, next) {
if (next.isAuthenticated) {
Navigator.pushNamed(context, '/home');
}
});
Explanation:
- No UI rebuild
- Used for navigation logic
- Reacts only to state changes
When to Use
Use WidgetRef when:
- You need to access providers in UI
- You want reactive updates (
watch) - You need to trigger actions (
read) - You need side effects (
listen) - You are inside any Riverpod widget
When NOT to Use
Avoid using WidgetRef when:
- You are outside Flutter widget tree
- You are inside pure Dart services
- You are writing business logic (use providers instead)
- You are not interacting with UI
Best Practices
- Use
watchonly inside build methods - Use
readfor actions and events - Use
listenfor side effects only - Avoid heavy logic inside widgets
- Keep providers responsible for business logic
- Prefer
ConsumerWidgetoverConsumerwhen possible
Common Mistakes
Using watch for One-Time Actions
Wrong
ref.watch(counterProvider);
Inside button callback or init logic.
Correct
ref.read(counterProvider);
Using read in Build for Reactive UI
Wrong
final value = ref.read(counterProvider);
UI will NOT update.
Correct
final value = ref.watch(counterProvider);
Misusing listen for UI Rendering
Wrong
ref.listen(provider, (_, next) {
return Text('$next');
});
listen is not for UI.
Correct
Use watch for UI, listen for side effects.
Related APIs
ConsumerWidgetConsumerStatefulWidgetConsumerref.watch()ref.read()ref.listen()ProviderAsyncValue
Summary
WidgetRef is the central interface between Flutter widgets and Riverpod. It enables widgets to react to provider changes, trigger actions, and handle side effects through watch, read, and listen, forming the core interaction layer of Riverpod’s UI integration.