ProviderElement<State> class
A provider that exposes a read-only value.
What is a provider
Providers are the most important components of Riverpod
. In short, you can think
of providers as an access point to a shared state.
Providers solve the following problems:
-
Providers have the flexibility of global variables, without their downsides.
Providers can be accessed from anywhere, while ensuring testability and scalability. -
Providers are safe to use.
As opposed to most service-locator solutions, using a provider, it is not possible to read a value in an uninitialized state.
If we can write the code to read a state, the code will execute properly. Even if the state is loaded asynchronously. -
Providers allow easily and efficiently listening to a piece of state.
They can be accessed in a single line of code, and offer many ways to optimize your application.
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 variables like so:
final myProvider = Provider((ref) {
return MyValue();
});
NOTE Do not feel threatened by the fact that a provider is declared as a global. While providers are globals, the variable is fully immutable. This makes creating a provider no different from declaring a function or a class.
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 calledref
as 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.
NOTE:
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":
final cityProvider = Provider((ref) => 'London');
final countryProvider = Provider((ref) => 'England');
The fact that both providers create a String
does not cause conflicts.
We will be able to read both values independently from each other without issue.
WARNING
For providers to work, you need to add ProviderScope
at the root of your
Flutter applications:
void main() {
runApp(ProviderScope(child: MyApp()));
}
Combining providers
We've previously seen how to create a simple provider. But the reality is, in many situations a provider will want to read the state of another provider.
To do that, we can use the ref
object passed to the callback of our provider,
and use its watch
method.
As an example, consider the following provider:
final cityProvider = Provider((ref) => 'London');
We can now create another provider that will consume our cityProvider
:
final weatherProvider = FutureProvider((ref) async {
// We use `ref.watch` to watch another provider, and we pass it the provider
// that we want to consume. Here: cityProvider
final city = ref.watch(cityProvider);
// We can then use the result to do something based on the value of `cityProvider`.
return fetchWeather(city: city);
});
That's it. We've created a provider that depends on another provider.
One interesting aspect of this code is, if city
ever changes,
this will automatically call fetchWeather
again and update the UI accordingly.
Creating an object that depends on a lot of providers.
Sometimes, we may want to create an object that depends on a lot of providers like so:
final cityProvider = Provider((ref) => 'London');
final countryProvider = Provider((ref) => 'England');
final weatherProvider = Provider((ref) {
final city = ref.watch(cityProvider);
final country = ref.watch(countryProvider);
return Location(city: city, country: country);
});
class Location {
Location({required this.city, required this.country});
final String city;
final String country;
String get label => '$city ($country)';
}
This can quickly become tedious.
In that situation, it may be reasonable to pass the ref
variable to our
object directly:
final cityProvider = Provider((ref) => 'London');
final countryProvider = Provider((ref) => 'England');
final weatherProvider = Provider((ref) {
// Pass the `ref` object to our `Location` class.
// `Location` will then be able to call `ref.read` to read the providers.
return Location(ref);
});
class Location {
Location(this._ref);
final Ref _ref;
String get label {
final city = _ref.read(cityProvider);
final country = _ref.read(countryProvider);
return '$city ($country)';
}
}
This avoids having to implement a constructor, which makes changes on the object easier.
This is fine as, as opposed to BuildContext
from Flutter, that ref
object
is completely independent from Flutter/the UI.
As such the object can still be shared and tested.
Disposing the resources the state is destroyed
During the lifetime of an application, the state associated with a provider may
get destroyed.
In this situation, we may want to perform a clean-up before the state destruction.
This is done by using the ref
object that is passed to the callback of all providers.
That ref
object exposes an onDispose
method, which can be used to listen to
the state destruction even to perform some task.
The following example uses ref.onDispose
to close a StreamController
:
final example = StreamProvider.autoDispose((ref) {
final streamController = StreamController<int>();
ref.onDispose(() {
// Closes the StreamController when the state of this provider is destroyed.
streamController.close();
});
return streamController.stream;
});
See also:
- Provider.autoDispose, to automatically destroy the state of a provider when that provider is no longer listened to.
- Provider.family, to allow providers to create a value from external parameters.
- Inheritance
-
- Object
- ProviderElementBase<
State> - ProviderElement
- Implemented types
-
- ProviderRef<
State>
- ProviderRef<
Constructors
-
ProviderElement(ProviderBase<
State> _provider) - A ProviderElementBase for Provider
Properties
- container → ProviderContainer
-
The ProviderContainer that owns this ProviderElementBase.
no setterinherited
- debugAssertDidSetStateEnabled → bool
-
Whether the assert that prevents requireState from returning
if the state was not set before is enabled.
no setterinherited
- hashCode → int
-
The hash code for this object.
no setterinherited
- hasListeners → bool
-
Whether this ProviderElementBase is currently listened to or not.
no setterinherited
- mounted → bool
-
Whether the element was disposed or not
no setterinherited
-
origin
→ ProviderBase<
Object?> -
The provider associated with this ProviderElementBase, before applying overrides.
no setterinherited
-
provider
→ ProviderBase<
State> -
The provider associated with this ProviderElementBase, after applying overrides.
no setterinherited
- requireState → State
-
Read the current value of a provider and:
no setterinherited
- runtimeType → Type
-
A representation of the runtime type of the object.
no setterinherited
- state ↔ State
-
Obtains the state currently exposed by this provider.
getter/setter pairoverride
Methods
-
buildState(
) → void -
Invokes create and handles errors.
inherited
-
create(
{required bool didChangeDependency}) → void -
Initialize a provider.
override
-
debugReassemble(
) → void -
A life-cycle executed when a hot-reload is performed.
inherited
-
dispose(
) → void -
Release the resources associated to this ProviderElementBase.
inherited
-
exists(
ProviderBase< Object?> provider) → bool -
Determines whether a provider is initialized or not.
inherited
-
flush(
) → void -
A utility for re-initializing a provider when needed.
inherited
-
getState(
) → Result< State> ? -
Obtains the current state, or null if the provider has yet to initialize.
inherited
-
invalidate(
ProviderOrFamily provider) → void -
Invalidates the state of the provider, causing it to refresh.
inherited
-
invalidateSelf(
) → void -
Invalidates the state of the provider, causing it to refresh.
inherited
-
listen<
T> (ProviderListenable< T> listenable, void listener(T? previous, T value), {void onError(Object error, StackTrace stackTrace)?, bool fireImmediately = false, void onDependencyMayHaveChanged()?}) → ProviderSubscription<T> -
Listen to a provider and call
listener
whenever its value changes.inherited -
listenSelf(
void listener(State? previous, State next), {void onError(Object error, StackTrace stackTrace)?}) → void -
Listens to changes on the value exposed by this provider.
inherited
-
mayNeedDispose(
) → void -
Life-cycle for when a listener is removed.
inherited
-
mount(
) → void -
Called the first time a provider is obtained.
inherited
-
noSuchMethod(
Invocation invocation) → dynamic -
Invoked when a nonexistent method or property is accessed.
inherited
-
notifyListeners(
) → void -
Notify dependents that this provider has changed.
inherited
-
onAddListener(
void cb()) → void -
A life-cycle for whenever a new listener is added to the provider.
inherited
-
onCancel(
void cb()) → void -
Add a listener to perform an operation when the last listener of the provider
is removed.
inherited
-
onDispose(
void listener()) → void -
Adds a listener to perform an operation right before the provider is destroyed.
inherited
-
onRemoveListener(
void cb()) → void -
A life-cycle for whenever a listener is removed from the provider.
inherited
-
onResume(
void cb()) → void -
A life-cycle for when a provider is listened again after it was paused
(and onCancel was triggered).
inherited
-
read<
T> (ProviderListenable< T> provider) → T -
Read the state associated with a provider, without listening to that provider.
inherited
-
readProviderElement<
T> (ProviderBase< T> provider) → ProviderElementBase<T> -
Reads the state of a provider, potentially creating it in the process.
inherited
-
readSelf(
) → State -
Returns the currently exposed by a provider
inherited
-
refresh<
T> (Refreshable< T> provider) → T -
Forces a provider to re-evaluate its state immediately, and return the created value.
inherited
-
runOnDispose(
) → void -
Executes the Ref.onDispose listeners previously registered, then clear
the list of listeners.
inherited
-
setState(
State newState) → void -
Update the exposed value of a provider and notify its listeners.
inherited
-
toString(
) → String -
A string representation of this object.
inherited
-
update(
ProviderBase< State> newProvider) → void -
Called when the override of a provider changes.
inherited
-
updateShouldNotify(
State previous, State next) → bool -
Called when a provider is rebuilt. Used for providers to not notify their
listeners if the exposed value did not change.
override
-
visitAncestors(
void visitor(ProviderElementBase element)) → void -
Visit the ProviderElementBases that this provider is listening to.
inherited
-
visitChildren(
{required void elementVisitor(ProviderElementBase element), required void notifierVisitor(ProxyElementValueNotifier element)}) → void -
Visit the ProviderElements of providers that are listening to this element.
inherited
-
watch<
T> (ProviderListenable< T> listenable) → T -
Obtains the state of a provider and causes the state to be re-evaluated
when that provider emits a new value.
inherited
Operators
-
operator ==(
Object other) → bool -
The equality operator.
inherited