Link:
- Provider (4.0.4): https://pub.dev/packages/provider
============================================================================
1. Provider
============================================================================
(Remove using SetState()
)
a. How to use Provider:
- C1: Use keyword
Consumer
@override
Widget build(BuildContext context) {
return Consumer<User>(
builder: (context, user, child) => Text(user.name),
);
}
- C2: Use keyword
Provider.of
@override
Widget build(BuildContext context) {
User user = Provider.of<User>(context);
return Container(
child: Text(user.name),
);
}
b. Use ChangeNotifierProvider:
c. Use MultiProvider:
(Beacuse a program have many method SetState()
)
@override
Widget build(BuildContext context) {
return MultiProvider(
providers: [
ChangeNotifierProvider(
create: (_) => Method1(),
),
ChangeNotifierProvider(
create: (_) => Method2(),
),
...
],
child: TestWidget1(),
);
}
- C1:
@override Widget build(BuildContext context) { Counter1 counter1 = Provider.of<Counter1>(context); Counter2 counter2 = Provider.of<Counter2>(context); ...
- C2:
@override Widget build(BuildContext context) { return MultiProvider( providers: [ Provider<Counter1>.value(value: Counter1()), Provider<Counter2>.value(value: Counter2()), ], child: Container(), ); ...
d. Use ValueNotifier:
e. Use Proxy Provider:
(Use for Dependency Injection
)
@override
Widget build(BuildContext context) {
return ChangeNotifierProvider<CounterModel>.value(
value: CounterModel(counterService: Provider.of(context)),
child: Consumer<CounterModel>(
builder: (context, model, child) => Center(
...
),
...
- Method
ProxyProvider
can inject 6 methodProxyProvider1, ProxyProvider2, ..., ProxyProvider6
ProxyProvider3<CounterApi1, CounterApi2, CounterApi3, CounterService>
f. Use Future Provider:
g. Use Stream Provider:
(Note: Don't use Bloc in Bloc)
class SearchBox extends StatefulWidget {
final SearchBloc bloc;
SearchBox({SearchBloc bloc}) : this.bloc = bloc;
@override
_SearchBoxState createState() => _SearchBoxState();
}
...
searchController.addListener(() {
widget.bloc.search(searchController.text); // handle
});
...
search(String query) {
if (query.isEmpty) {
searchController.sink.add(dataSearch);
return;
}
_filter(query).then((result) {
// push value to Stream
searchController.sink.add(result);
});
}
...
@override
Widget build(BuildContext context) {
return Container(
child: StreamBuilder<List<String>>(
initialData: [],
stream: widget.bloc.searchController.stream,
builder: (context, snapshot) {
return ListView.builder(
itemCount: snapshot.data.length,
itemBuilder: (context, index) {
return _buildRow(snapshot.data[index]);
});
}),
);
}
...
@override
void didChangeDependencies() {
super.didChangeDependencies();
// get bloc on context
var bloc = Provider.of<SearchBlocProvider>(context);
searchController.addListener(() {
bloc.search(searchController.text);
});
}
...
@override
Widget build(BuildContext context) {
return Consumer<SearchBlocProvider>(
builder: (context, bloc, child) => Container(
child: StreamBuilder<List<String>>(
initialData: [],
stream: bloc.searchController.stream,
builder: (context, snapshot) {
return ListView.builder(
itemCount: snapshot.data.length,
itemBuilder: (context, index) {
return _buildRow(snapshot.data[index]);
});
}),
),
);
}
...