riverpod_kit
Riverpod for DartNative apps. It rebuilds
flutter_riverpod's widget layer on DartNative with the same names, so code
written for Flutter's Riverpod ports by changing one import.
// import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:riverpod_kit/riverpod_kit.dart';
Riverpod itself is used unchanged: providers, Notifier,
AsyncNotifier, families, riverpod_annotation and riverpod_generator.
Why this package
- Every
flutter_riverpodwidget you use daily.ProviderScope,UncontrolledProviderScope,ConsumerWidget,ConsumerStatefulWidget/ConsumerState,Consumer, andWidgetRefwithwatch,read,listen,listenManual,refresh,invalidateandexists. - Works on pushed screens and in sheets. In DartNative, a route pushed
with
Navigator.pushand the body ofshowModalSheetare separate widget trees, so an inherited lookup from inside them never reaches theProviderScopearound your root screen.riverpod_kitfalls back to the app's root container, so aConsumerWidgetbehaves the same on any screen or sheet. - Rebuilds only what it must. Subscriptions made during a build are replaced on the next build, so a provider a widget no longer watches stops rebuilding it.
| Home | Pushed screen and sheet |
|---|---|
![]() |
![]() |
Install
dependencies:
riverpod_kit:
hosted: https://dartpub.dev
version: ^0.1.0
dn pub get
Add riverpod_annotation and riverpod_generator as usual if you use code
generation; they need nothing DartNative-specific.
Use
import 'package:dartnative/dartnative.dart';
import 'package:riverpod_kit/riverpod_kit.dart';
import 'dartnative_plugin_registrant.dart';
final counterProvider = NotifierProvider<Counter, int>(Counter.new);
class Counter extends Notifier<int> {
@override
int build() => 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) {
final count = ref.watch(counterProvider);
return Scaffold(
body: Center(
child: Button(
title: 'Count: $count',
onPressed: () => ref.read(counterProvider.notifier).increment(),
),
),
);
}
}
A container built before runApp
Create the container yourself when startup must await something first (restoring a session, reading stored settings) or needs overrides. You own it and dispose it.
Future<void> main() async {
DartNativePluginRegistrant.registerAll();
final container = ProviderContainer(overrides: [/* ... */]);
await container.read(sessionProvider.future);
runApp(UncontrolledProviderScope(container: container, child: const App()));
}
Stateful widgets
class DetailScreen extends ConsumerStatefulWidget {
const DetailScreen({super.key});
@override
ConsumerState<DetailScreen> createState() => _DetailScreenState();
}
class _DetailScreenState extends ConsumerState<DetailScreen> {
@override
void initState() {
super.initState();
ref.listenManual(counterProvider, (previous, next) => dnLog('$next'));
}
@override
Widget build(BuildContext context) =>
Text('Count: ${ref.watch(counterProvider)}');
}
Outside the widget tree
ProviderScope.containerOf(context) returns the nearest container, else the
root one. ProviderScope.rootContainer is the root container, or null before
any scope is mounted.
Rules
They are the same as flutter_riverpod's:
- Call
ref.watchandref.listenonly insidebuild. - Use
ref.listenManualininitStateand callbacks; it is closed with the widget. - Don't use
refafterdispose. It throws, as in Flutter. This includessetStateorrefcalls in an async callback that finishes after the screen has gone.
Example
example/lib/main.dart shows one counter shared by
a root screen, a pushed ConsumerStatefulWidget and a Consumer inside a
sheet.
cd example && dn run
Differences from flutter_riverpod
ProviderScope.rootContainerand the root fallback are additions. Flutter doesn't need them, because its routes inherit from above the app.- The
ProviderScopeparent, if any, is the nearest scope above, else the root container. There is noparent:parameter.
Credits
The API mirrors flutter_riverpod
by Remi Rousselet (MIT). This package is an independent implementation on
DartNative and depends on riverpod
unchanged.
License
MIT, see LICENSE.

