π± 20 / 100 Days Of Flutter, Kate's edition β intro into Riverpod with Providers, Consumers and AsyncValue
How are you doing, Flutter community? π
On my side, I'm happy to share with you the 20th update on my Flutter learning challenge!
Finally, I started learning Riverpod state manager which positions itself as "A Reactive Caching and Data-binding Framework". My learning is driven by the amazing Andrea's blog and course. I will share some bits with you here but you can always head to his website and find tons of high-quality Flutter materials.
Providers
My introduction to Riverpod started with providers and consumers. I don't fully understand how it works, but it already makes sense.
Providers are the most important part of a Riverpod application. A provider is an object that encapsulates a piece of state and allows listening to that state.
Riverpod providers reminded me of Redux's reducers but Riverpod implementation is much more powerful as it supports async and streams out of the box.
To start writing providers, I installed the "Flutter Riverpod Snippets" plugin (available for Android Studio and VS Code).
Typing "str" or "futu" brings a list of snippet suggestions just like on the screenshot above.
Providers are declared as global variables which is an uncommon practice for the Flutter ecosystem. The official documentation asks us not to worry about it:
Do not be frightened by the global aspect of providers. Providers are fully immutable. Declaring a provider is no different from declaring a function, and providers are testable and maintainable.
I personally like keeping things simple and not worried at all π
Consumers
First and foremost, before reading a provider, we need to obtain a "ref" object. This object is what allows us to interact with providers, be it from a widget or another provider.
The next step is to obtain (consume) values from the providers. To continue React Redux analogy, ConsumerWidget
and Consumer
are somewhat similar to Redux Connect API. They allow you to obtain that magic ref
object and then you can start watching or listening to any providers you need.
class HomeView extends ConsumerWidget {
const HomeView({Key? key}): super(key: key);
@override
Widget build(BuildContext context, WidgetRef ref) {
// use ref to listen to a provider
final counter = ref.watch(counterProvider);
return Text('$counter');
}
}
The code snippet above is from the official Riverpod documentation (which is very good btw!)
AsyncValue
What I really like about Riverpod is its completeness. Instead of the "doing one thing well" approach, the library covers all popular use cases. For instance, async support is a first-class citizen in Riverpod.
Riverpod has FutureProvider
and StreamProvider
for async and reactive use cases. Listening to these types of providers returns an AsyncValue
β which allows handling of the error/loading states.
class Example extends ConsumerWidget { // Inheriting from ConsumerWidget to get access to ref.
@override
Widget build(BuildContext context, WidgetRef ref) {
final AsyncValue<User> user = ref.watch(userProvider); // Watching FutureProvider or StreamProvider
// Using AsyncValue utility to handle async
return user.when(
loading: () => CircularProgressIndicator(),
error: (error, stack) => Text('Oops, something unexpected happened'),
data: (value) => Text('Hello ${user.name}'),
);
}
}
The code snippet above is from the official Riverpod documentation.
You can read more about AsyncValue in Andrea's blog.
Widget of the day - CircularProgressIndicator
It's really cool to have beautiful progress indicators available as part of the framework. Flutter comes with CircularProgressIndicator
and LinearProgressIndicator
. You could see an example use case in the AsyncValue
code snippet - if the data is loading, you can simply return CircularProgressIndicator()
. If you need something more sophisticated, there are plenty of configuration parameters.
If it's still not enough, there are contrib packages like Shimmer.
Summary
Today I've learned a lot about Riverpod. It's a robust and powerful library that covers many practical use cases like async, caching, autoDispose, etc. Of course, it has a certain learning curve, so I will continue exploring it in the coming days.
If you'd like to connect or collaborate on the Flutter learning process, catch @kalabro on Twitter π