provider_scope
Riverpod-backed ProviderScope primitives for DartNative apps.
provider_scope brings Riverpod's container model to DartNative's
widget tree. It provides a DartNative ProviderScope, ConsumerWidget, and
WidgetRef so app code can read and watch Riverpod providers from DartNative
widgets.
The package depends on package:riverpod and re-exports its core APIs,
including Provider, ProviderContainer, NotifierProvider, FutureProvider,
and StreamProvider.
Features
- Use Riverpod providers from DartNative widgets.
- Rebuild DartNative widgets with
ref.watch(provider). - Read providers without listening with
ref.read(provider). - React to provider changes with
ref.listen(provider, listener). - Imperatively subscribe with
ref.listenManual(provider, listener). - Refresh or invalidate providers from the widget layer.
- Pass Riverpod overrides directly to
ProviderScope. - Access the underlying
ProviderContainerwhen needed.
Installation
Add the package to your DartNative app:
dependencies:
provider_scope: ^0.3.0
Then run:
dn pub get
Basic Usage
Wrap your DartNative app with ProviderScope.
import 'package:dartnative/dartnative.dart';
import 'package:provider_scope/provider_scope.dart';
import 'dartnative_plugin_registrant.dart';
final counterProvider = NotifierProvider<Counter, int>(Counter.new);
final messageProvider = Provider<String>((ref) {
final count = ref.watch(counterProvider);
return 'Count: $count';
});
class Counter extends Notifier<int> {
@override
int build() {
return 0;
}
void increment() {
state++;
}
}
void main() {
DartNativePluginRegistrant.registerAll();
runApp(const ProviderScope(child: HomeScreen()));
}
class HomeScreen extends ConsumerWidget {
const HomeScreen({super.key});
@override
Widget build(BuildContext context, WidgetRef ref) {
ref.listen<int>(counterProvider, (previous, next) {
dnLog('Counter changed from ${previous ?? 0} to $next');
});
final message = ref.watch(messageProvider);
return Button(
title: message,
onPressed: () {
ref.read(counterProvider.notifier).increment();
},
);
}
}
ref.watch(provider) subscribes the ConsumerWidget to provider changes. When
the provider emits a new value, the widget rebuilds.
ref.read(provider) reads the current value without subscribing.
ref.listen(provider, listener) subscribes to provider changes for side effects
such as logging, navigation, persistence, or analytics. The subscription is
closed automatically when the ConsumerWidget is disposed.
ref.listenManual(provider, listener) returns a ProviderSubscription that can
be paused, resumed, read, or closed manually. It is also closed automatically
when the ConsumerWidget is disposed.
ref.refresh(provider) forces a provider to recompute immediately and returns
the new value. ref.invalidate(provider) marks a provider or family for refresh.
Use ref.exists(provider) to check whether a provider is already initialized.
Overrides
Pass Riverpod overrides directly to ProviderScope.
final apiBaseUrlProvider = Provider<String>((ref) {
return 'https://api.example.com';
});
ProviderScope(
overrides: [
apiBaseUrlProvider.overrideWithValue('https://staging.example.com'),
],
child: const HomeScreen(),
);
Parent Containers
You can pass a parent ProviderContainer when composing scopes:
final parent = ProviderContainer();
ProviderScope(
parent: parent,
child: const HomeScreen(),
);
Container Access
If you need direct access to Riverpod's container, use
ProviderScope.containerOf(context).
final container = ProviderScope.containerOf(context);
final value = container.read(messageProvider);
For most UI code, prefer ref.watch(provider) and ref.read(provider) inside a
ConsumerWidget.
Example
See example/lib/main.dart for a small counter app built with ProviderScope.