Riverpod — Part 1
Introduction
Usually, I’ll choose MobX for state management, and it goes well with get_it. A combination that worked for me well for many projects.
I had this unique Retina Coach project that teaches young doctors how to be a surgeon. I based it on the FireStore database. I needed a great solution with data streams, so I decided to give riverpod a try since it has excellent support for that. Another lovely side effect of using rivderpod instead of MobX is that I won’t need the locator I use (get_it).
About the app
RetinaCoach is an educational app for learning about retina surgeries. The main feature is video sharing from expert surgeons around the world.
A short showcase of the app and features
Subjects are
What is riverpod?
How to implement authentication with firebase authentication and riverpod.
Using flutter_hooks is a more accessible and cleaner way to use Riverpod.
I am using Riverpod and Firestore's real-time database.
Offline mode
How to test Riverpod?
What is Riverpod?
Riverpod is state management for Flutter. The package is similar to the well-known Provider (same creator) but has some significant advantages. It is compiled safe and has no limitations as a provider has. If compared to MobX, you don’t need to wait hours for the build_runner to generate your code. Riverpod support multiple providers of the same type, combining asynchronous Provider and adding providers from anywhere. Also, there are stream providers to handle stream sources. Also, Create/share/test providers with no dependency on Flutter. So you will be able to listen to providers without a BuildContext.
Installation:
The first step is to add the latest version of flutter_riverpod as a dependency to our pubspec.yaml file: (by this time)
hooks_riverpod: ^0.13.1+1
ProviderScope
void main() {
runApp(ProviderScope(
child: MyApp(),
));
}
Consume the provider
To consume the providers, we will use flutter_hooks (an exciting library you can check this article) by calling useProvider(providerName).
Types of providers:
Provider
The most simple of all, the Provider can hold any data. Although I often use it to get objects (I used GetIt to do this job before). you cannot change the state of a simple Provider.
Riverpod providers use ref watch() to access providers by reference, not by type. This means we can have as many providers as we want of the same kind. we can also use ref.read(provider) to read it just once and not listen to its changes like ref.watch(…)
* you can call read/watch also with context.read() or context.watch() let’s say from a button.
StateProvider
Sane as Provider, but you can change the state of it. So when we use the useProvider in our HookWidget, we have a getter and a setter to state that we can read and write. Changes will automatically build the UI.
Get the provider in the HookWidget under build from the widget and manipulate its state.
StateNotifier + StateNotifierProvider
This one is the most complex of them, reminding me of BLoC. First, you set a class with a state that makes updates/manipulations(update notifications are sent when you manipulate the state).
The difference between StateNotifierProvider and StateProvider or Provider is that it should be used when the data is more complex. If you are using only simple stuff like getting a Repository or holding state with an enum, you better use the Provider or the StateProvider.
ChangeNotifierProvider
The original Provider package used ChangeNotifierProvider, and now with Riverpod, I prefer to use the StateNotifierProvider instead. It is good to create view models. the way to use it is to call manually notifyListeners()
and it will rebuild the UI.
class NoteModel extends ChangeNotifier { String note = ''; void updateNote(String text) { note = text; notifyListeners(); }
void clear() { note = ''; notifyListeners(); }}
FutureProvider
I love this one. When doing any asynchronous tasks, FutureProvider is the way to go. What I like about it is that you can call `when` and get: data, loading, error states (Triple state). just like you would do every time with freeze class.
StreamProvider
Kind of FutureProvider but for streams of data. For example, a socket or if you want to listen to changes on your Firestore database.
The difference between Stream and Future is that the FutureProvider will only execute once and end. An excellent example of the RetinaCoach app is that it listens to the favorite status of each video.
notice that .autoDispose on the provider (line 1)? If we’re working with FutureProvider or StreamProvider, we’ll want to dispose of any listeners when our provider is no longer in use.
We can also call ref.onDispose() from FutureProvider or Stream Provider to perform some custom cancellation logic.
After it, I added .family. Its purpose is to pass a variable to the Provider from outside. In this case, I pass the videoId.
Conclusion
This article mainly focused on explaining the moving parts of Riverpod, although I know I skipped some of its features, and I hope to cover them in the upcoming articles for this series.
The following article will focus on how to implement authentication with Firebase using Riverpod. in RetinaCoach, I need the identity of a user so I can save his/her favorites and notes. Still, there’s no need for a username/password or authentication with a provider like Google or Apple. The next chapter will focus on the Firebase structure and authentication with some examples of saving a video as a favorite.
You are welcome to join my Flutter community (“Flutter Israel”). This group is a non-profit group made ❤️ by Flutter developers for Flutter developers, based in Israel (IL). You are welcome to post job opportunities and share your knowledge. LINK
RetinaCoach Android version: LINK
I hope you enjoyed it!