가령 두개의 다른 타입의 ChangeNotifierProvider가 존재하고 한 위젯에서 이 모두에게 접근해야할 때 사용
만약 여러개의 Provider가 계층 구조를 이룬다면 가독성도 떨어지고 코드가 효율적으로 보이지 않음
Provider(
create: (context) => ModelA(),
child: Provider(
create: (context) => ModelB(),
child: Provider(
create: (context) => ModelC(),
child: MaterialApp(),
),
),
);
MultiProvider(
provider:[
Provider(create: (context) => ModelA,
Provider(create: (context) => ModelB,
Provider(create: (context) => ModelC,
],
child: MaterialApp(),
);
일반적으로 Future를 반환하는 함수를 사용하여 값을 제공하는 Provider
주가 지수와 같이 연속되는 future value는 StreamBuilder로 값을 보여준다.
하지만 만약 Stream 값을 여러 위젯에서 access 하고자 한다면 StreamProvider를 사용하는 것이 좋다.
class Babies {
final int age;
Babies({required this.age});
Future<int> getBabies() async {
await Future.delayed(Duration(seconds: 3));
if (age > 1 && age < 5) {
return 4;
} else if (age < 1) {
return 0;
} else {
return 2;
}
}
Stream<String> bark() async* {
for (int i = 1; i < age; i++) {
await Future.delayed(Duration(seconds: 2));
yield 'Bark $i times';
}
}
}
// provider
Widget build(BuildContext context) {
return MultiProvider(
providers: [
ChangeNotifierProvider<Dog>(
create: (context) => Dog(name: 'dog', breed: 'breed', age: 3),
),
FutureProvider<int>(
initialData: 0,
create: (context) {
final int dogAge =
context.read<Dog>().age;
// 상위 프로바이더 값 사용 가능
final babies = Babies(age: dogAge);
return babies.getBabies();
},
),
StreamProvider(
initialData: 'Bark 0 times',
create: (context) {
final int dogAge = context.read<Dog>().age;
final babies = Babies(age: dogAge * 2);
return babies.bark();
}
),
],
child: MaterialApp(
...
);
}
// 사용하는 부분
Text(
'- number of babies : ${context.watch<int>()}',
// future 함수의 리턴타입이 int이기 때문
),
Text(
'- ${context.watch<String>()}',
// stream 함수의 리턴타입이 string이기 때문,
//
),
상태 관리와 빌드 최적화를 간단하게 처리할 수 있도록 도와주는 중요한 요소
class _MyHomePageState extends State<MyHomePage> {
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Provider 08'),
),
body: Consumer<Dog>(
builder: (BuildContext context, Dog dog, Widget? child) {
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
mainAxisSize: MainAxisSize.min,
children: [
child!,
// rebuild 하고 싶지 않음 - 이럴 때 사용하는 것이 builder의 세번째 인자 child
SizedBox(height: 10.0),
Text(
'- name: ${dog.name}',
style: TextStyle(fontSize: 20.0),
),
SizedBox(height: 10.0),
BreedAndAge(),
],
),
);
},
child: Text(
'i like dogs very much',
style: TextStyle(fontSize: 20.0),
),
),
);
}
}
Consumer위젯과 거의 유사, Consumer보다 더 세세한 컨트롤할 수 있게 해주는 위젯
셀렉터 위젯을 사용할 때 selector 콜백에서 업데이트할 항목만 골라서
builder의 인자로 넘겨줄 수 있음 property가 많은 오브젝트라면 굉장히 좋은 솔루션
build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Provider 08'),
),
body: Selector<Dog, String>( // <오브젝트타입, 선택할 프로퍼티의 타입>
selector: (BuildContext context, Dog dog) => dog.name,
builder: (BuildContext context, String name, Widget? child) {
// Consumer와 마찬가지로 rebuild 제외할 child 지정 가능
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
mainAxisSize: MainAxisSize.min,
children: [
child!,
SizedBox(height: 10.0),
Text(
'- name: $name',
style: TextStyle(fontSize: 20.0),
),
SizedBox(height: 10.0),
BreedAndAge(),
],
),
);
},
child: Text(
'i like dogs very much',
style: TextStyle(fontSize: 20.0),
),
),
);
}
Widget