Enhance Flutter state management with Riverpod
Take your Flutter development to the next level with Riverpod: A Journey into advanced state management
In this article, we’ll be exploring Riverpod in-depth. We’ll cover all the important parts of Riverpod, any limitations you might face, and effective solutions to overcome them. Let’s dive in!
let’s start this by understanding why we need Riverpod in the first place, there are some problems with a provider which cannot be fixed some of those problems include confusing and tedious syntax from proxy provider multiple providers not having the same return data type and the infamous provider not found an exception.
To counter these problems riverpod was written however riverpod is not just a state management solution anymore it is also a replacement for many design patterns like Singleton, dependency injections, and service locators it also helps in fetching caching and canceling Network requests while also handling the error cases to get started head to pubspec.yaml file and make sure you have the latest version of flutter riverpod installed.
riverpod is divided into three packages hooks_riverpod flutter_riverpod and riverpod, hooks_riverpod is used with flutter hooks flutter_riverpod with the flutter SDK and the riverpod with dart programs, which means you can create cli using riverpod
after having that in place go to the main.dart file wraps your root Widget the widget that’s passed in the run app with a widget known as providerscope this provides a scope widget that is a constant and it comes from the flutter riverpod package this provider scope keeps track of all the providers and ensures that there is no leakage of State in spite of the providers being declared globally.
Global Declaration of providers or variables in general means if suppose I have a variable like string “title” and I’ve declared it outside of any function and outside of any class I’ve declared it globally usually Global declaration be it of variables or providers should be a problem because of mutability issues meaning if a non-constant variable like this
the title is declared its value can be changed by any function for example if I have the main function right here I can change the value of the title over here
right, so I can type my title as flutter_riverpod, so imagine this for hundreds and thousands of files you are able to change this, so do you think it’s a good practice absolutely not because it would be very difficult to know which function changed the value of the title and if we ever want it or not and to find it will be a big task and we generally don’t want to do that so you might think if this is prohibited why does provider or riverpod even do this,
The reason for that is the providers declared globally in riverpod are immutable and this is for all the providers in riverpod they all are immutable except one, so let’s discuss all types of Providers one by one.
Provider
The first type of Provider is the provider itself, riverpod has multiple providers which can give us access to the State whatever state we want to access for them, each provider has its own purpose so the very first type of provider is providing it is called provider.
if you are coming from a provider package you already know about it as the name suggests
it is an object that provides data to Widgets or other providers it is a read-only widget and cannot update the value inside of it it can be used to provide primitive non-primitive data types and even instances of classes to create a provider.
While a Provider
in Riverpod is useful for exposing values and services to other parts of your application, it does not inherently provide a way to manage state. This is where the StateProvider
comes in.
StateProvider
so for that, we have the second type of Provider which is the State provider, State provider is used to update the value from outside which is not possible using the provider it is like an upgrade over the normal provider.
The StateProvider
is a type of provider that allows you to expose a value that can be read and modified across your application. When you modify the value, any widgets that are watching it will be rebuilt to reflect the updated value.
now there comes a third type of Provider which StateNotifierProvider
basically, it is an upgrade over the state provider, basically state provider is used for very simple values like a string that we had over here and integer values double values a Boolean values but what about complex values for example if you want to modify or manipulate the values inside of a class what if I want to update a map there will be many functions, I’m not saying we can’t do that with the state provided it’s definitely possible but our logic will be lying around in our widgets so we don’t want to make make our logic lie around in the widgets as programmers we want our logic to be together in a single place and most likely a class.
StateNotifierProvider
This is where StateNotifierProvider
comes in handy. By using a StateNotifier
class to manage complex states, we can encapsulate all the logic for updating that state in one place. This allows us to separate concerns and keep our code organized and maintainable.
For example, let’s say we have a User
class that contains various properties such as name, email, age, and address. We could use a StateNotifierProvider
to manage the state of the User
object and provide a clean and organized way to modify and access its properties throughout the app.
Here’s an example of how we could use a StateNotifierProvider
to manage the state of an User
object:
so the next type of provider is the changeNotifierProvider, if you are using a provider then you already know about it because it directly comes from Riverpod to easily migrate from provider to Riverpod because many of the functions in the provider have changed Notifier class.
that’s why it’s there for easy transition but however, in the Riverpod documentation it’s mentioned that we shouldn’t use much of a changeNotifierProvider if you are building our application from scratch it’s always recommended to use a StateNotifierProvider.
changeNotifierProvider
but let’s for understanding, ChangeNotifierProvider
is a widget in the Flutter Riverpod state management library that provides an instance of a ChangeNotifier
to its descendants. Its purpose is to listen to changes in the provided ChangeNotifier
instance and notify its descendants to rebuild when a change occurs.
Here’s an example of how you can use ChangeNotifierProvider
Riverpod:
however, if you have a provider-used project and it’s pretty big to convert then you can use it but it’s not recommended and I would also recommend you to not do so now after having a brief knowledge of the change notifier provider, let’s jump to next type of provider is the future provider.
FutureProvider
FutureProvider as the name suggests is a provider based on HTTP calls or asynchronous code even Firebase calls so when this FutureProvider is used for futures.
so if you have asynchronous code you’ll definitely be using the future provider and it will make your life much easier it is kind of a replacement and a shorter code for future Builder and a better one in my opinion.
FutureProvider is a provider that allows you to expose a value that may not be available immediately but will be available at some point in the future. This is useful when you need to perform an asynchronous operation to obtain a value, such as fetching data from a server.
For example, you could use FutureProvider to fetch user data from a server and expose it to your app. The FutureProvider would handle the asynchronous operation of fetching the data and updating the UI once the data is available.
now after having this future provider let’s move on to the final type of provider in the Riverpod package which is the stream provider.
StreamProvider
A StreamProvider
can be useful when you need to listen to an event stream, such as user interactions or changes to a database.
so as we see all types of providers, what are the features that are available to us and it’s not just for future providers or stream providers it’s available to every single provider.
I talking about well it’s the modifiers, modifiers is a function that is used to modify or enhance the behavior of a Provider. Modifiers are used to add additional functionality to Providers, such as caching, lazy initialization, or filtering.
Here are some examples of modifiers in Riverpod:
.family
: This modifier is used to create a family of Providers that share similar behavior. For example, you could create a family of HTTP Clients that share the same base URL..autoDispose
: This modifier is used to automatically dispose of a Provider when it is no longer being used. This can be useful for Providers that consume resources, such as database connections..overrideWithValue
: This modifier is used to override the value of a Provider with a new value. This can be useful for testing or for providing mock data..state
: This modifier is used to create a Provider that manages a mutable state value. This can be useful for managing UI state, such as whether a button is disabled or enabled.
like here is an example code snippet that shows how to use the .autoDispose
modifier in a StreamProvider
:
In this example, the StreamProvider
exposes a stream of integers that emits a new value every second for five seconds. The .autoDispose
modifier is set to true
, which means that the provider will automatically dispose of the stream subscription when it is no longer needed, such as when the widget that uses it is removed from the widget tree. This helps to prevent memory leaks and unnecessary resource usage.
Modifiers can be combined to create more complex Providers with custom behaviors. For example, you could create a Provider that automatically disposes of itself and caches its value using the .autoDispose
and .cached
modifiers.
so now we are done with all the types of providers we have had six providers to look at to give you a refresh of that provider is a read-only object so if you want to provide a value be it primitive data types like integer Boolean string you can use them or non-primitive data type like list map whatever or even instances of classes. second state provider, it is like an upgrade of the normal provider if you just want to update a simple State like an integer value or a Boolean. the third one is the StateNotifier provider this is generally used when there are more complex states to be dealt with for example the user class and we want to modify their properties or whatever. the fourth one is changeNotifierProvider it’s recommended not to use by Riverpod it’s just for the transition from provider to Riverpod if you have a bigger code base this will help you but if you’re starting from scratch or you have a smaller project I would recommend you to not use it because of its mutable state. fifth one is the FutureProvider so if you have asynchronous code and you want to avoid the Roth of this future Builder and async snapshot you can use future provider. sixth one and the final one is StreamProvider so if you have a stream and of course, you want to get rid of the stream Builder and async snapshot again you can use stream provider it is reusable and with and it should help you a lot all right now after knowing all of the providers there are some methods on ref that I want to talk about.
ProviderObserver
the last thing that I want to talk about in this flutter riverpod package is something known as a ProviderObserver now I told you if there are Global variables it would be very difficult to understand where the provider is being added where it’s being removed where it’s being listened so it is quite a task but with access to this something known as a ProviderObserver you can log these things out.
ProviderObserver
is a widget in the Riverpod state management library that allows you to observe changes to a provider, and react to them accordingly.
Here’s an example code snippet that shows how to use ProviderObserver
to display a counter:
you can create this with a separate class as well, for just understanding purposes I write all this in one page, basically, here we use a StateProvider
to create a provider that holds an integer. We then use a ConsumerWidget
to build a widget that displays the value of the provider. We use ProviderScope
to override the state of the provider with a new value of 42 and then use ref.watch(myProvider)
to listen to changes to the provider's state. We use ScopedProviderRef
to access the state of the provider within the context of the ProviderScope
. We also use the .autoDispose
modifier to ensure that the overridden provider is automatically disposed of when it is no longer needed.
That’s all the information I wanted to share about Riverpod. In comparison with Provider, Riverpod offers a better solution for managing the state in Flutter. As a result, it addresses the limitations of Provider and enables a robust architecture for your Flutter application, enabling you to build a reliable application from the ground up. In addition, I obtained all the information from a variety of websites as part of some research, so if you find any errors or misdirected links, please let me know.
If you got something wrong? Mention it in the comments. I would love to improve. your support means a lot to me! If you enjoy the content, I’d be grateful if you could consider subscribing to my YouTube channel as well.
I am Shirsh Shukla, a creative Developer, and a Technology lover. You can find me on LinkedIn or maybe follow me on Twitter or just walk over my portfolio for more details. And of course, you can follow me on GitHub as well.
Have a nice day!🙂