provider 3.0.0 provider: ^3.0.0 copied to clipboard
A dependency injection system built with widgets for widgets. provider is mostly syntax sugar for InheritedWidget, to make common use-cases straightforward.
A dependency injection system built with widgets for widgets. provider
is mostly syntax sugar for InheritedWidget
,
to make common use-cases straightforward.
Migration from v2.0.0 to v3.0.0 #
- Providers can no longer be instantiated with
const
. Provider
now throws if used with aListenable
/Stream
. Consider usingListenableProvider
/StreamProvider
instead. Alternatively, this exception can be disabled by settingProvider.debugCheckInvalidValueType
tonull
like so:
void main() {
Provider.debugCheckInvalidValueType = null;
runApp(MyApp());
}
- All
XXProvider.value
constructors now usevalue
as parameter name.
Before:
ChangeNotifierProvider.value(notifier: myNotifier),
After:
ChangeNotifierProvider.value(value: myNotifier),
StreamProvider
's default constructor now builds aStream
instead ofStreamController
. The previous behavior has been moved to the named constructorStreamProvider.controller
.
Before:
StreamProvider(builder: (_) => StreamController<int>()),
After:
StreamProvider.controller(builder: (_) => StreamController<int>()),
Usage #
Exposing a value #
To expose a variable using provider
, wrap any widget into one of the provider widgets from this package
and pass it your variable. Then, all descendants of the newly added provider widget can access this variable.
A simple example would be to wrap the entire application into a Provider
widget and pass it our variable:
Provider<String>.value(
value: 'Hello World',
child: MaterialApp(
home: Home(),
)
)
Alternatively, for complex objects, most providers expose a constructor that takes a function to create the value.
The provider will call that function only once, when inserting the widget in the tree, and expose the result.
This is perfect for exposing a complex object that never changes over time without writing a StatefulWidget
.
The following creates and exposes a MyComplexClass
. And in the event where Provider
is removed from the widget tree,
the instantiated MyComplexClass
will be disposed.
Provider<MyComplexClass>(
builder: (context) => MyComplexClass(),
dispose: (context, value) => value.dispose()
child: SomeWidget(),
)
Reading a value #
The easiest way to read a value is by using the static method Provider.of<T>(BuildContext context)
. This method will look
up in widget tree starting from the widget associated with the BuildContext
passed and it will return the nearest variable
of type T
found (or throw if nothing if found).
Combined with the first example of exposing a value, this widget will read the exposed String
and render "Hello World."
class Home extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Text(
/// Don't forget to pass the type of the object you want to obtain to `Provider.of`!
Provider.of<String>(context)
);
}
}
Alternatively instead of using Provider.of
, we can use the Consumer
widget.
This can be useful for performance optimizations or when it is difficult to obtain a BuildContext
descendant of the provider.
Provider<String>.value(
value: 'Hello World',
child: Consumer<String>(
builder: (context, value, child) => Text(value),
),
);
Note that you can freely use multiple providers with different types together:
Provider<int>.value(
value: 42,
child: Provider<String>.value(
value: 'Hello World',
child: // ...
)
)
And obtain their value independently:
var value = Provider.of<int>(context);
var value2 = Provider.of<String>(context);
MultiProvider #
When injecting many values in big applications, Provider
can rapidly become pretty nested:
Provider<Foo>.value(
value: foo,
child: Provider<Bar>.value(
value: bar,
child: Provider<Baz>.value(
value: baz,
child: someWidget,
)
)
)
In that situation, we can use MultiProvider
to improve the readability:
MultiProvider(
providers: [
Provider<Foo>.value(value: foo),
Provider<Bar>.value(value: bar),
Provider<Baz>.value(value: baz),
],
child: someWidget,
)
The behavior of both examples is strictly the same. MultiProvider
only changes the appearance of the code.
Existing providers #
provider
exposes a few different kinds of "provider" for different types of objects.
name | description |
---|---|
Provider | The most basic form of provider. It takes a value and exposes it, whatever the value is. |
ListenableProvider | A specific provider for Listenable object. ListenableProvider will listen to the object and ask widgets which depend on it to rebuild whenever the listener is called. |
ChangeNotifierProvider | A specification of ListenableProvider for ChangeNotifier. It will automatically call ChangeNotifier.dispose when needed. |
ValueListenableProvider | Listen to a ValueListenable and only expose ValueListenable.value . |
StreamProvider | Listen to a Stream and expose the latest value emitted. |
FutureProvider | Takes a Future and updates dependents when the future completes. |