riverpod
riverpod copied to clipboard
Add offline persistence support
Riverpod should allow simple integration with offline storage solutions
A possibility is to have Riverpod serialize/deserialize the current state of a provider and send that to a database, associated with a unique key corresponding to the provider.
This sounds interesting. I might give this a try. Do you already have an idea in mind? If so can you share some classes I should look into to be able to implement a draft for this functionality?
:wave: thanks for offering to help, but this specific issue is in a bit of a unique position. I'd like to personally take care of this one
I don't know if it's gonna be bad,
But I would say, you might want to take a look https://github.com/flutterdata/flutter_data
or
https://flutterdata.dev/docs/repositories/#architecture-overview
Finally, thank you for your library : ) (Translated above)
This feature is not really related to what you're suggesting
What this issue involves will most likely be two bits:
-
new parameters on providers for decoding/encoding:
final provider = SomeProvider( (ref) {}, name: 'unique_key', decode: (data) => MyClass.fromJson(data), encode: (value) => value.toJson(), );
-
a way to tell ProviderScope/ProviderContainer how to obtain the encoded value of a provider
ProviderScope( initialData: { 'unique_key': { <some json> }, }, encoder: SomeDBEncoder(), ),
this sounds very interesting, is this being added to the roadmap? @rrousselGit
this sounds very interesting, is this being added to the roadmap? @rrousselGit
It is on the roadmap for https://github.com/rrousselGit/river_pod/milestone/1
You mentioned this issue in #1168 and while the scope of this feature doesn't seem as narrow as just restoring the state after the OS kills your app, I thought you might be interested in this lib I recently made that restores the state of providers: https://github.com/North101/flutter_riverpod_restorable
@North101 the repo link does not work, so I'll leave a link to your package:
I needed a solution for a generic riverpod persistence layer, and ended up with this:
https://github.com/tim-smart/riverpod_persistence/blob/main/test/riverpod_persistence_test.dart
Would be nice to have something official!
Personally, I really like how states_rebuilder handles state persistence. This lets the user choose how offline data is stored while at the same time, abstracting away the actual storing of the data unless they want to. This solution would also help to mitigate any potential migration issues as the developer would be able to use their existing local storage provider.
That state_rebuild persistence wiki looks very similar to what I plan on doing for Riverpod. Thanks for sharing!
Supporting ChangeNotifier and the current StateNotifier may be difficult though.
I think I'll have to implement this feature only for the new StateNotifier syntax if that's OK.
Supporting ChangeNotifier and the current StateNotifier may be difficult though.
I think I'll have to implement this feature only for the new StateNotifier syntax if that's OK.
@rrousselGit Can you clarify what you mean by the "new StateNotifier syntax"? Are you talking about the one that's already released in 2.0 dev or an unreleased one?
An unreleased one.
I've talked about the new syntax on twitter/discord before. It would be:
final provider = NotifierProvider<MyNotifier, int>(MyNotifier.new);
class MyNotifier extends Notifier<int> {
@override
int create() {
ref.watch(something);
return 0;
}
}
With an async variant:
final provider = AsyncNotifierProvider<MyNotifier, int>(MyNotifier.new);
class MyNotifier extends AsyncNotifier<int> {
@override
Future<int> create() async {
ref.watch(something);
return 0;
}
}
I'll add offline persistence slightly after the 2.0 release
There will be a 2.1 about of month after the 2.0 with it. There's no reason to delay the 2.0 release since that's a new feature :smile:
I'll add offline persistence slightly after the 2.0 release
There will be a 2.1 about of month after the 2.0 with it. There's no reason to delay the 2.0 release since that's a new feature 😄
when will version 2 be released?
Somewhere during september.
I was going to implement my own version of riverpod x persisted state, but just discovered that it's in the official roadmap, can't wait :)
Does the feature need to be delayed?
No it's still plannes for 2.1
What this issue involves will most likely be two bits:
- new parameters on providers for decoding/encoding:
final provider = SomeProvider( (ref) {}, name: 'unique_key', decode: (data) => MyClass.fromJson(data), encode: (value) => value.toJson(), );
- a way to tell ProviderScope/ProviderContainer how to obtain the encoded value of a provider
ProviderScope( initialData: { 'unique_key': { <some json> }, }, encoder: SomeDBEncoder(), ),
I think a common pattern might be:
- Fetch data from the server
- Cache fetched data locally
Then in the future:
- Supply provider with local cached value
- If you so desire, fetch the value from the server to repopulate cache
Would something like the following be a way of going about that (assuming we are using the new NotifierProvider
syntax with riverpod_generator
)?
Stream<TheDataType> build() async* {
yield await fetchFromDisk(); // would this be needed? or will decode handle this?
yield await fetchFromServer();
}
And then perhaps there will be a separate encode/persist method that will cache the value locally on state change as suggested?
Or would it be just simply:
Future<TheDataType> build() {
ref.watch(cacheRepopulationTimerProvider); // force fetching new data at some set times, perhaps at app launch
return fetchFromServer();
}
Because the decode would handle the fetching from disk and everything else for you before build
is called (or would build
be called at all if the encoder finds the value stored on disk? Maybe having some sort of check whether it should get called, like the cacheRepopulationTimerProvider
above, would be ideal?).
In any case, I think the Stream generator syntax could be a clean way of handling multiple steps, but the second option with just the Future<TheDataType>
shows intent better.
Edit: Perhaps the encoder SomeDBEncoder
could actually handle fetching data from the server as well? But that would hurt readability/intent--someone reading the code might not know where the true data is coming from.
I see https://pub.dev/packages/hydrated_riverpod extension which is supporting offline persistence support just like https://pub.dev/packages/hydrated_bloc for Bloc.
thought worth mentioning
Any updates regarding this feature? Will it be soon released?
Is there a recommended way to emulate this functionality before it's merged?
I'm using AsyncNotifier
with codegen and want to cache the latest network states using my selected storage library; currently just write to disk every time a _fetch()
completes and hydrate in build()
. Should I be using something like ref.onDispose
inside build()
? I don't use watch()
inside build
though, just await
my network calls
I got side-tracked by working on lint rules for Riverpod. I'll release those soon and see if I get pick this up next.
Although there are good candidates for other features, like #1660
@Rizzaxc I recently implemented a workaround for my project that's working well so far. It's using disk storage to save revisions on every change event and restores the latest revision when the app starts: https://github.com/kwiesmueller/cypher_sheet/blob/main/lib/state/observer.dart
It's my first time using riverpod, but this has been working well since I added it.
@rrousselGit What problem feature solve? Is this meant as a tool to enable an offline first app functionality? Allow groundwork for some kind of custom database online/offline sync? Or as a more flexible and feature rich local storage?
I don't think I fully understand what all this would do.
@FXschwartz Riverpod's goal in general is to do as much as possible for typical complex apps.
So ideally it should work for offline first apps.
@FXschwartz Riverpod's goal in general is to do as much as possible for typical complex apps.
So ideally it should work for offline first apps.
Would you ever consider adding on to this some kind of handler that would react to the app going online/offline?
Right now one of Firestore's biggest advantages is that is handles offline/online data syncing for you without having to do anything extra. If you want this functionality with another database like Mongodb for instance you'd have to create your own custom data syncing.
Not sure if that scope would be more than Riverpod should be responsible for but I think it would be really valuable.