A generic implementation of InheritedWidget
. It allows to expose any kind of object, without having to manually write an InheritedWidget
ourselves.
To expose a value, simply wrap any given part of your widget tree into any of the available Provider
as such:
Provider<int>(
value: 42,
child: // ...
)
Descendants of Provider
and now obtain this value using the static Provider.of<T>
method:
var value = Provider.of<int>(context);
You can also use Consumer
widget to insert a descendant, useful when both creating a Provider
and using it:
Provider<int>(
value: 42,
child: Consumer<int>(
builder: (context, value) => Text(value.toString()),
)
)
Note that you can freely use multiple providers with different type together:
Provider<int>(
value: 42,
child: Provider<String>(
value: 'Hello World',
child: // ...
)
)
And obtain their value independently:
var value = Provider.of<int>(context);
var value2 = Provider.of<String>(context);
A simple provider which takes the exposed value directly:
Provider<int>(
value: 42,
child: // ...
)
A provider that can also create and dispose an object.
It is usually used to avoid making a StatefulWidget
for something trivial, such as instanciating a BLoC.
StatefulBuilder
is the equivalent of a State.initState
combined with State.dispose
.
As such, valueBuilder
is called only once and is unable to use InheritedWidget
; which makes it impossible to update the created value.
If this is too limiting, consider instead HookProvider
, which offer a much more advanced control over the created value.
The following example instanciate a Model
once, and dispose it when StatefulProvider
is removed from the tree.
class Model {
void dispose() {}
}
class Stateless extends StatelessWidget {
@override
Widget build(BuildContext context) {
return StatefulProvider<Model>(
valueBuilder: (context) => Model(),
onDispose: (context, value) => value.dispose(),
child: ...,
);
}
}
A provider which can use hooks from flutter_hooks
This is especially useful to create complex providers, without having to make a StatefulWidget
.
The following example uses BLoC pattern to create a BLoC, provide its value, and dispose it when the provider is removed from the tree.
HookProvider<MyBloc>(
hook: () {
final bloc = useMemoized(() => MyBloc());
useEffect(() => bloc.dispose, [bloc]);
return bloc;
},
child: // ...
)
A provider that merges multiple other providers into one.
MultiProvider
is used to improve the readability and reduce the boilerplate of
having many nested providers.
As such, we're going from:
Provider<Foo>(
value: foo,
child: Provider<Bar>(
value: bar,
child: Provider<Baz>(
value: baz,
child: someWidget,
)
)
)
To:
MultiProvider(
providers: [
Provider<Foo>(value: foo),
Provider<Bar>(value: bar),
Provider<Baz>(value: baz),
],
child: someWidget,
)
Technically, these two are identical. MultiProvider
will convert the array into a tree.
This changes only the appearance of the code.
A provider that exposes the current value of a Stream
as an AsyncSnapshot
.
Changing [stream] will stop listening to the previous [stream] and listen the new one.
Removing [StreamProvider] from the tree will also stop listening to [stream].
To obtain the current value of type T
, one must explicitly request Provider.of<AsyncSnapshot<T>>
.
It is also possible to use StreamProvider.of<T>
.
Stream<int> foo;
StreamProvider<int>(
stream: foo,
child: Container(),
);
Expose the current value of a [ValueListenable].
Changing [valueListenable] will stop listening to the previous [valueListenable] and listen the new one. Removing [ValueListenableProvider] from the tree will also stop listening to [valueListenable].
ValueListenable<int> foo;
ValueListenableProvider<int>(
valueListenable: foo,
child: Container(),
);
Expose a [ChangeNotifier] subclass and ask its depends to rebuild whenever [ChangeNotifier.notifyListeners] is called
Listeners to [ChangeNotifier] only rebuilds when [ChangeNotifier.notifyListeners] is called, even if [ChangeNotifierProvider] is rebuilt.
class MyModel extends ChangeNotifier {
int _value;
int get value => _value;
set value(int value) {
_value = value;
notifyListeners();
}
}
// ...
ChangeNotifierProfider<MyModel>.stateful(
builder: () => MyModel(),
child: Container(),
)