Now that we have installed Riverpod, let's talk about "providers".
Providers are the most important part of a Riverpod application.
A provider is an object that encapsulate a piece of state and allows listening to that state.
Why use providers?
By wrapping a piece of state in a provider, this:
Allows easily accessing that state in multiple locations.
Providers are a complete replacement for patterns like Singletons, Service Locators, Dependency Injection or InheritedWidgets.
Simplifies combining this state with others.
Ever struggled merging multiple objects into one? This scenario is built directly inside providers, with a simple syntax.
Enables performance optimisations.
Whether for filtering widget rebuilds or for caching expensive state computations; providers ensure that only what is impacted by a state change is recomputed.
Increases the testability of your application.
With providers, you do not need complex
tearDownsteps. Furthermore, any provider can be overridden to behave differently during test, which allows easily testing a very specific behavior.
Easily integrate with advanced features, such as logging or pull-to-refresh.
Creating a provider
Providers come in many variants, but they all work the same way.
The most common usage is to declare them as global constant like so:
Do not be afraid by the global aspect of providers.
Providers are fully immutable. Declaring a provider is no different from declaring a function, and is testable and maintainable.
This snippet consist of three components:
final myProvider, the declaration of a variable.
This variable is what we will use in the future to read the state of our provider. It should always be immutable.
Provider, the provider that we decided to use.
Provider is the most basic of all providers. It exposes an object that never changes.
We could replace Provider with other providers like StreamProvider or StateNotifierProvider, to change how the value is interacted with.
A function that creates the shared state.
That function will always receive an object called
refas a parameter. This object allows us to read other providers or to perform some operations when the state of our provider will be destroyed.
The type of the object created by the function passed to a provider depends on
the provider used.
For example, the function of a Provider can create any object. On the other hand, StreamProvider's callback will be expected to return a Stream.
You can declare as many providers as you, want without limitations.
As opposed to when using
package:provider, in Riverpod we can have two
providers expose a state of the same "type":
The fact that both providers create a
String does not cause any problem.
For providers to work, you must add ProviderScope at the root of your Flutter applications:
Performing actions before the state destruction
In some cases, the state of a provider may get destroyed or re-created.
A common use-case in those situations is to perform a cleanup before the state of a provider
is destroyed, such as closing a
This is done using the
ref object, which is passed to the callback of all providers, using its onDispose method.
The following example uses onDispose to close a
Depending on the provider used, it may already take care of the clean-up process.
For example, StateNotifierProvider will call the
dispose method of a
All Providers have a built-in way to add extra functionalities to your different providers.
They may add new features to the
ref object or change slightly how the provider
Modifiers can be used on all providers, with a syntax similar to named constructor:
At the moment, there are two modifiers available:
.autoDispose, which will make the provider automatically destroy its state when it is no-longer listened.
.family, which allows creating a provider from external parameters.
A provider can use multiple modifiers at once:
That's it for this guide!