Provider
는 Flutter에서 상태 관리의 문제를 해결하기 위한 패키지로, 특히 Prop Drilling 문제를 효과적으로 해결할 수 있는 도구입니다. InheritedWidget
을 보다 쉽게 사용할 수 있도록 래핑하여 상태 관리를 더 간단하고 효율적으로 만들어줍니다.
InheritedWidget
을 래핑하여 더 쉽게 상태를 관리하고, 필요한 부분에서만 상태를 갱신할 수 있도록 도와줍니다.notifyListeners()
메서드를 호출하여 상태 변경을 알립니다.ChangeNotifier
를 사용하는 Provider
의 한 종류로, 상태 객체를 제공하고 관리합니다.Provider
의 상태를 구독하여 변경될 때마다 빌드하는 위젯.StatefulWidget
보다 유지 관리가 용이합니다.InheritedWidget
보다 코드량이 적습니다.ChangeNotifierProvider
: ChangeNotifier
객체를 제공하는 Provider입니다.Consumer
: Provider
에서 제공하는 상태를 구독하고, 상태가 변경될 때마다 빌드합니다.context.watch<T>()
: Provider
에서 상태를 구독하고 변경 시 위젯을 다시 빌드합니다.context.read<T>()
: 상태를 구독하지 않고 읽기만 합니다.context.select<T, R>(R selector(T value))
: 특정 속성만 구독하여 변경 시에만 빌드합니다.ChangeNotifier 클래스 작성
class Counter with ChangeNotifier {
int _count = 0;
int get count => _count;
void increment() {
_count++;
notifyListeners();
}
}
ChangeNotifierProvider로 상태 주입
void main() {
runApp(
ChangeNotifierProvider(
create: (context) => Counter(),
child: MyApp(),
),
);
}
Consumer를 사용하여 상태 접근 및 UI 업데이트
class MyApp extends StatelessWidget {
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text('Provider Example'),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text('You have pushed the button this many times:'),
Consumer<Counter>(
builder: (context, counter, child) {
return Text(
'${counter.count}',
style: Theme.of(context).textTheme.headline4,
);
},
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: () {
Provider.of<Counter>(context, listen: false).increment();
},
tooltip: 'Increment',
child: Icon(Icons.add),
),
),
);
}
}
context.watch()
: notifyListeners()
호출 시 위젯 갱신
ProviderCart providerCart = context.watch<ProviderCart>();
isInCart: providerCart.cartProductList.contains(product),
onPressed: providerCart.onProductPressed,
context.read()
: notifyListeners()
호출 시 갱신하지 않음
onPressed: context.read<ProviderCart>().onProductPressed,
context.select()
: 특정 속성이 변경된 경우에만 갱신
List<Product> cartProductList = context.select<ProviderCart, List<Product>>(
(providerCart) => providerCart.cartProductList,
);
Consumer
: watch
와 동일하나 특정 위젯만 갱신
Consumer<Counter>(
builder: (context, counter, child) {
return Text(
'${counter.count}',
style: Theme.of(context).textTheme.headline4,
);
},
);
Selector
: select
와 동일하나 특정 위젯만 갱신
Selector<ProviderBadge, int>(
selector: (context, providerBadge) => providerBadge.counter,
builder: (context, counter, child) => BottomBar(
currentIndex: currentIndex,
cartTotal: "$counter",
onTap: (index) => setState(() {
currentIndex = index;
}),
),
),
ChangeNotifierProvider
: 변경 사항을 알릴 필요가 있는 클래스
ChangeNotifierProvider(
create: (context) => ProviderCart(),
)
Provider
: 변경 사항을 알릴 필요가 없는 클래스
Provider(
create: (context) => MyService(),
)
initState()
에서 Provider에 접근하려면 StatefulWidget의 속성에서 Provider를 생성해야 합니다.ChangeNotifierProvider
로 등록한 Provider는 해당 StatefulWidget이 위젯 트리에서 제거될 때 함께 dispose()
됩니다.void initState() {
super.initState();
Provider.of<MyProvider>(context, listen: false).fetchData();
}
class MyBadge with ChangeNotifier {
MyBadge(this.myCart) {
myCart.addListener(_update);
}
final MyCart myCart;
int _count = 0;
void _update() {
_count = myCart.items.length;
notifyListeners();
}
void dispose() {
myCart.removeListener(_update);
super.dispose();
}
}