오늘은 Consumer 에 대해서 정리했습니다.
개발환경 : 윈도우11, 안드로이드 스튜디오(Arctic Fox 2020.3.1 Patch 4), flutter 2.10
소스코드 위치 - https://github.com/mike-bskim/provider_overview/releases/tag/setState_to_Consumer1
화면은 이전 블로그와 동일한 구조입니다. 각 위젯별로 다른 방식으로 상태관리를 한다.
Counter A - Provider
Middle - context.read()
Counter B - Consumer+Provider
Sibling - Consumer
콘솔 로그는 아래와 같다.
Provider 로 상태관리한 CounterA 만 전체 빌드를 다시하고 , Middle 은 context.read() 를 이용하여 최초 로딩시에만 빌드하고, CounterB 는 Provider 를 사용하지만 Consumer 로 감싸서 사용하니 해당 영역만 빌드를 한다(전체 빌드가 실행되지 않음). Sibling 는 Consumer 만 사용하여 해당 영역만 빌드된다. 그래서 로그에는 CounterA 관련 로그만 출력된다.
I/flutter ( 5855): -----------------------------------
I/flutter ( 5855): MyApp >> build
I/flutter ( 5855): MyHomePage >> build
I/flutter ( 5855): ===================================
I/flutter ( 5855): CounterA >> build
I/flutter ( 5855): Middle >> build
I/flutter ( 5855): Sibling >> build
I/flutter ( 5855): CounterB >> build
I/flutter ( 5855): ===================================
I/flutter ( 5855): CounterA >> build
I/flutter ( 5855): ===================================
I/flutter ( 5855): CounterA >> build
전체 소스코드는 "더보기" 클릭하세요
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
void main() {
runApp(const MyApp());
}
class Counter with ChangeNotifier {
String titleCounterA = 'Counter A';
String titleCounterB = 'Counter B';
String titleMiddle = 'Middle';
String titleSibling = 'Sibling';
int counter = 0;
void increment() {
counter++;
notifyListeners();
}
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
debugPrint('-----------------------------------');
debugPrint('MyApp >> build');
return MaterialApp(
title: 'Counter',
debugShowCheckedModeBanner: false,
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({Key? key}) : super(key: key);
@override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
@override
Widget build(BuildContext context) {
debugPrint('MyHomePage >> build');
return Scaffold(
appBar: AppBar(
title: const Text('My Counter'),
),
body: ChangeNotifierProvider<Counter>(
create: (context) => Counter(),
child: Center(
child: Container(
color: Colors.grey,
padding: const EdgeInsets.all(16.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
mainAxisSize: MainAxisSize.min,
children: const <Widget>[
Text('MyHomePage', style: TextStyle(fontSize: 24.0)),
SizedBox(height: 20.0),
CounterA(),
SizedBox(height: 20.0),
Middle(),
],
),
),
),
),
);
}
}
class CounterA extends StatelessWidget {
const CounterA({
Key? key,
}) : super(key: key);
@override
Widget build(BuildContext context) {
debugPrint('===================================');
debugPrint('CounterA >> build');
return Container(
color: Colors.red[100],
padding: const EdgeInsets.all(20.0),
child: Column(
children: [
Text(Provider.of<Counter>(context).titleCounterA),
Text(
'${Provider.of<Counter>(context).counter}',
style: const TextStyle(fontSize: 48.0),
),
ElevatedButton(
onPressed: Provider.of<Counter>(context, listen: false).increment,
child: const Text(
'Increment',
style: TextStyle(fontSize: 20.0),
),
),
],
),
);
}
}
class Middle extends StatelessWidget {
const Middle({
Key? key,
}) : super(key: key);
@override
Widget build(BuildContext context) {
debugPrint('Middle >> build');
return Container(
color: Colors.grey[200],
padding: const EdgeInsets.all(20.0),
child: Column(
children: [
Text(context.read<Counter>().titleMiddle),
const SizedBox(height: 20),
Row(
mainAxisAlignment: MainAxisAlignment.center,
mainAxisSize: MainAxisSize.min,
children: const [
CounterB(),
SizedBox(width: 20.0),
Sibling(),
],
),
],
),
);
}
}
class CounterB extends StatelessWidget {
const CounterB({
Key? key,
}) : super(key: key);
@override
Widget build(BuildContext context) {
debugPrint('CounterB >> build');
return Consumer<Counter>(
builder: (BuildContext context, Counter cnt, Widget? child) {
return Container(
color: Colors.yellow[100],
padding: const EdgeInsets.all(10.0),
child: Column(
children: [
Text(Provider.of<Counter>(context).titleCounterB),
Text(
'${cnt.counter}',
style: const TextStyle(fontSize: 24.0),
),
],
),
);
},
);
}
}
class Sibling extends StatelessWidget {
const Sibling({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
debugPrint('Sibling >> build');
return Consumer<Counter>(
builder: (BuildContext context, Counter cnt, Widget? child) {
return Container(
color: Colors.orange[100],
padding: const EdgeInsets.all(10.0),
child: Column(
children: [
Text(cnt.titleSibling),
const Text(
'Sibling',
style: TextStyle(fontSize: 24.0),
),
],
),
);
},
);
}
}
Selector 는 특정 변수를 지정해서 상태관리를 할 수 있다.
Sibling 위젯을 아래와 같이 수정할 수 있다.
class Sibling extends StatelessWidget {
const Sibling({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
debugPrint('Sibling >> build');
return Selector<Counter, String>(
selector: (context, Counter cnt) => cnt.titleSibling,
builder: (BuildContext context, String title, Widget? child) {
return Container(
color: Colors.orange[100],
padding: const EdgeInsets.all(10.0),
child: Column(
children: [
Text(title),
const Text(
'Sibling',
style: TextStyle(fontSize: 24.0),
),
],
),
);
},
);
}
}
소스코드 위치 - https://github.com/mike-bskim/provider_overview/releases/tag/setState_to_Selector
'Flutter > 07 State - Provider' 카테고리의 다른 글
[Flutter] Provider Access - Named route (0) | 2022.05.06 |
---|---|
[Flutter] Provider Access - Anonymous route (0) | 2022.05.06 |
[Flutter] Could not find the correct Provider (0) | 2022.05.05 |
[Flutter] ChangeNotifierProvider (0) | 2022.05.04 |
[Flutter] setState (0) | 2022.05.04 |