rrousselGit / state_notifier

ValueNotifier, but outside Flutter and with some extra perks
MIT License
311 stars 28 forks source link

Automatic persistence? #44

Open wujek-srujek opened 3 years ago

wujek-srujek commented 3 years ago

Is your feature request related to a problem? Please describe. I use a StateNotifier for state management (with riverpod) and I got it to work. However, now I would like to persist the state so that it survives application restarts.

Describe the solution you'd like Libraries that I have used before, like redux or bloc, both support automatic persistence, normally as separate packages (redux_persist and hydrated_bloc). I have looked around and it seems that there is nothing out of the box for state_notifier. I understand it is not hard to do myself, but I expect a lot of people to have to write very similar code to solve this. Would it be possible to also have some kind of automatic persistence?

For serialization on state changes, I think the easiest way that would work for all StateNotifiers would be to do it in a listener - whenever it is fired, it schedules a write. I suppose this could be a separate package like state_notifier_persistence, which offers some abstraction layer (like an abstract Storage interface, with a possible default implementation with hive (it seems to be the go-to library for things like this in Flutter), possibly in yet another package, like state_notifier_persistence_hive. state_notifier_persistence would also provide the said listener (PersistingListener?) which takes an instance of Storage and uses it.

For deserialization (i.e. when a StateNotifier is created and there already exist state in storage) I don't have a nice API in mind yet. One option would be to have a mixin that provides storage and overrides the state getter and if the state is null, it uses storage to read it from disk. I beliveve this is what hydrated_bloc does.

Describe alternatives you've considered I've implemented it myself for my application (very dirty, very ugly for now, no abstraction over hive etc., it is just a PoC). As far as I know, there are no alternatives to this, except migrating away to other state-management libraries.

rrousselGit commented 3 years ago

That's something I plan to implement (in riverpod, not statenotifier). But it requires refinement. I don't want to release a bad API So it's going to take a while

wujek-srujek commented 3 years ago

Why not state_notifier? This would make it broadly available even without riverpod.

rrousselGit commented 3 years ago

RIverpod has more to restore than just statenotifiers. For example we may want to persist a Future/StreamProvider

wujek-srujek commented 3 years ago

Right. But why not implement persistence for state_notifier so that it works for state_notifier without riverpod, and then implement in riverpod whatever needs to be persisted, possibly with some further improvements for state_notifier? It seemed to me you wanted people to use state_notifier no matter if they used riverpod or not (but I can imagine you would like all of us to use riverpod as well ;-)), and this would also help adoption.

Bottomline is: if you do it in riverpod only, there will be this strange situation where state_notifier will be kind of a standalone library, but will need riverpod for persistence, but riverpod is much more than that and not everybody will like/use it and be willing to include just to get persistence for state_notifier. In this case I would question if state_notifier is the way to go as with each such decision it will force me more and more towards riverpod, which I might not necessarily like (well, I personally do, but not everyone will).

rrousselGit commented 3 years ago

I don't like the idea of shipping a solution if I haven't thought all the cases through.

A quick API may work in the sort-term. But it may require a large breaking change or the coexistence of two competing APIs within the same library.
I wouldn't want StateNotifier to have one way of doing deserialisation and Riverpod have another way for example. That'd be confusing

wujek-srujek commented 3 years ago

That's not at all what I am saying, I don't want to use a half-assed API either. I don't know where this comes from, seriously. If half a year is necessary to implement a good solution, so be it. What I was arguing was that state_notifier, as a standalone package independent of riverpod, should have its own automatic persistence, is all.

rrousselGit commented 3 years ago

Ah sorry, I wanted to say that I don't think it is possible to have the best API possible just with StateNotifier.

venkatd commented 3 years ago

Just another perspective, but I like that StateNotifier is a robust and focused library. Adding persistence to it would increase its scope for a feature that many people may not use.

Implementing persistence is use case specific. Where do you store the persisted data? How do you serialize the state? When do you persist and when do you restore? Do you debounce this logic? It all depends on the application and I bet it's varies a lot depending on the app.

On the other hand, implementing something like PersistentStateNotifier that extends/wraps StateNotifier and persists data for your specific app is likely not a lot of code.

Perhaps you could share your use case? We have something like this lying around in our codebase that I can share when I get a chance.

wujek-srujek commented 3 years ago

That's why I said that it could be in a separate package, like a lot of state management libraries do, e.g. hydrated_bloc or redux_persist_flutter. It is possible to parameterize all that you mention, as the mentioned libraries, and many more, were able to do and came up with an API for it (which most of the time is some kind of Storage abstraction with a few methods like put, get etc., and various implementations, with Hive and JSON being very popular choices).

Of course I can implement the PersistentStateNotifier myself, the point is - everybody will need to do it if they need state persistence, an everybody will do it differently, which is unnecessary effort. Also, everybody will have their own little bugs; if it is in a package that is used by many, this would not happen as often as it would be battle-tested by real world apps.

I'm arguing that any state management library without the ability to persist the state out-of-the-box isn't complete. But anyways, yeah, I have already understood that you don't want this for whatever reason, so I guess the topic can be closed.

tim-smart commented 2 years ago

I stumbled upon this issue looking for a generic persistence layer on top of riverpod.

As a result, I have started a proof of concept solution. You can view the working test case here: https://github.com/tim-smart/riverpod_persistence/blob/main/test/riverpod_persistence_test.dart