Riverpod topic
Refena for Riverpod developers
Introduction
You might have noticed that Refena is similar to Riverpod.
However, there are still some things that need your attention when you want to migrate from Riverpod to Refena.
Providers
Riverpod | Refena |
---|---|
Provider |
Provider for immutable values, ViewProvider for reactive values |
StateProvider |
StateProvider (no change) |
FutureProvider |
FutureProvider (no change) |
StreamProvider |
StreamProvider (no change) |
ChangeNotifierProvider |
ChangeNotifierProvider (no change) |
StateNotifierProvider |
NotifierProvider (drop the State part) |
NotifierProvider |
NotifierProvider (no change) |
AsyncNotifierProvider |
AsyncNotifierProvider (no change) |
Family providers:
Riverpod | Refena |
---|---|
Provider.family |
ViewProvider.family (only reactive version available) |
FutureProvider.family |
FutureProvider.family (no change) |
Other | Not supported |
New providers:
Refena | Description |
---|---|
ViewProvider |
The only provider that can watch other providers |
ReduxProvider |
A provider where you dispatch actions to get the new state |
No ConsumerWidget or ConsumerStatefulWidget
In Refena, there is no ConsumerWidget
or ConsumerStatefulWidget
.
You can access the providers directly in the build
method:
class MyPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
final counter = context.watch(counterProvider);
return Text('$counter');
}
}
AutoDispose
In Refena, providers never dispose themselves automatically.
Instead, you need to call ref.dispose(provider)
manually (usually in a StatefulWidget
's dispose
method):
class MyPage extends StatefulWidget {
@override
_MyPageState createState() => _MyPageState();
}
class _MyPageState extends State<MyPage> {
@override
void dispose() {
context.dispose(counterProvider);
super.dispose();
}
@override
Widget build(BuildContext context) {
final counter = context.watch(counterProvider);
return Text('$counter');
}
}
Use ViewModelBuilder
or FamilyViewModelBuilder
widgets to dispose providers automatically.
Access notifiers
A slight difference between Riverpod and Refena is how you access the notifiers.
Riverpod | Refena |
---|---|
ref.read(provider.notifier) |
ref.notifier(provider) |
Listener
In Riverpod, you can listen to a provider by calling ref.listen(provider, (prev, next) {})
.
In Refena, there are two ways to listen to a provider:
Outside the build
method:
final subscription = ref.stream(provider).listen((prev, next) {});
Inside the build
method:
final state = ref.watch(provider, (prev, next) {
// This callback is called whenever the provider changes
});
Lifespan of Ref
Compared to Riverpod,
the ref
object in Refena is always available because it's just a wrapper around RefenaContainer
.
You will never need to worry about the lifespan of ref
.
NotifierProvider
In Refena, the NotifierProvider
looks like this:
final counterProvider = NotifierProvider<Counter, int>((ref) {
return Counter();
});
class Counter extends Notifier<int> {
@override
int init() => 0;
void increment() => state++;
}
Notice that there is a ref
parameter in the NotifierProvider
's builder function.
All providers have this parameter to allow you to use the Dependency Injection pattern.
Also, the Notifier
class has the init
method that returns the initial state.
This is similar to the build
method in Riverpod.
StateProvider
To change the state of a StateProvider
, there is a slight difference between Riverpod and Refena.
Riverpod | Refena |
---|---|
ref.read(provider.notifier).state++ |
ref.notifier(provider).setState((old) => old + 1) |
You need to access the notifier first to keep the code consistent with other providers.
Classes
- RefenaContainer Introduction Riverpod Initialization
- The RefenaContainer holds the state of all providers. Every provider state is initialized lazily and only once.
- RefenaContainer Introduction Riverpod Initialization
- The RefenaContainer holds the state of all providers. Every provider state is initialized lazily and only once.