Jaspr Riverpod
A port of the riverpod package for Jaspr.
Jaspr comes with a Riverpod package that ports over flutter_riverpod
to Jaspr. It is based
on Riverpod 2 and supports all providers and modifiers.
Accessing Providers
While it has feature-parity for defining Provider
s, it comes with some quality-of-life improvements
on the Consumer
side. Mainly:
It does not have Consumer
, ConsumerWidget
or StatefulConsumerWidget
. This is because it
does not rely on WidgetRef
to access providers but instead comes with context extensions on the
BuildContext
of any component.
As an example, this (in Flutter):
// need to extend custom ConsumerWidget
class MyWidget extends ConsumerWidget {
// need to accept custom WidgetRef
Widget build(BuildContext context, WidgetRef ref) {
// uses ref to access providers
var value = ref.watch(myProvider);
return Text(value);
}
}
is equivalent to this (in Jaspr)
// just extends the normal component
class MyComponent extends StatelessComponent {
// no extra parameter
Iterable<Component> build(BuildContext context) sync* {
// uses context to access providers
var value = context.watch(myProvider);
yield Text(value);
}
}
The extension on BuildContext
supports all the normal methods from `WidgetRef``
context.read()
,context.watch()
,context.refresh()
,context.invalidate()
,context.listen()
Replacement for Consumer
Same as with ConsumerComponent
, we don't need the Consumer
anymore. If you want only parts of your
component tree to rebuild when watching a provider, simply use the Builder
component. This will
give you a new context which you can call context.watch
on:
Builder(builder: (context) sync* {
var value = context.watch(...);
yield /* ... */;
});
Preloading and Syncing Provider State
Jaspr allows StatefulComponent
s to preload state as well as sync state between server and client
(when using server-side rendering).
Since providers often are used to replace StatefulComponent
s, jaspr_riverpod
offers the same
mechanisms inside a special provider, called SyncProvider
:
final mySyncProvider = SyncProvider<int>((ref) async {
// do some async work on the server, like fetching data from a database
await Future.delayed(Duration(seconds: 1));
return 100;
}, id: 'initial_count');
This provider needs an additional id to be synced with the client.
The create function of a SyncProvider
is only executed on the server, and
never on the client. Instead the synced value is returned.
It then can be used like any other provider. It functions like a FutureProvider
and exposes a
value of type AsyncValue<T>
.
Backstory: Why context extensions instead of Consumer?
Put simply: Because they are easier and more flexible to use and require less boilerplate.
The actual question would be why they are not part of flutter_riverpod in the first place.
This is because mainly context.watch
is not feasible in flutter_riverpod
.
This is a limitation by Flutter itself, not Riverpod. There are long standing bugs
(or missing features depending on how you view it)
in flutter with InheritedWidget
that make it impossible for context.watch
to work properly.
Recently there have been efforts by the creator
of riverpod to fix these bugs,
but without success.
As jaspr
is basically a complete rewrite of flutters core framework, I went ahead and fixed
these bugs and thereby making context.watch
feasible.