상태관리
1. 컨텍스트가 분리되어 있지 않으면 전체가 다시 그려진다
상태 관리와 재구성:
- Flutter에서는 상태가 변경되면 그와 관련된 위젯 트리가 다시 빌드됩니다.
- 불필요한 위젯 트리 전체의 재구성을 막기 위해 상태를 변경할 필요가 없는 위젯과 변경이 필요한 위젯을 구분하는 것이 매우 중요합니다.
2.텍스트를 분리하여, 상태가 변경되는 부분만 StatefulWidget
(SF)로 만든다.
컨텍스트 분리:
- 상태가 변경되더라도 영향을 받지 않아야 하는 부분(위젯)을
StatelessWidget
으로 만들고, 상태가 변경되는 부분만StatefulWidget
으로 만듭니다.
- 이를 통해 성능을 최적화하고, 불필요한 재구성을 방지할 수 있습니다.
3.그림을 그리다 보면, 상태의 화면과 행위의 화면이 다를 때가 있다.
부모 위젯에서 상태 관리:
- 상태가 여러 자식 위젯에 영향을 미치는 경우, 부모 위젯에서 상태를 관리하고 자식들에게 그 상태와 상태를 변경하는 함수를 전달합니다.
- 이 패턴을 사용하면 상태와 행위를 명확하게 분리할 수 있고, 유지보수가 용이해집니다.
이러한 개념을 적용하면, Flutter에서 성능을 유지하면서 상태를 효율적으로 관리하고 위젯을 다시 그리는 문제를 최소화할 수 있습니다.
1. Flutter는 상태를 가지고 그림을 그린다.
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
home: HomePage(),
);
}
}
class HomePage extends StatefulWidget {
@override
State<HomePage> createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
int num = 1;
@override
Widget build(BuildContext context) {
print("빌드됨");
return Scaffold(
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text("번호 : $num", style: TextStyle(fontSize: 30)),
MyContainer(), // new를 두번 하지 않는다. 이것은 내가 제어 할 수 있따.
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: () {
num++;
setState(() {});
print("num : $num");
},
child: Icon(Icons.add),
),
);
}
}
class MyContainer extends StatelessWidget {
const MyContainer();
@override
Widget build(BuildContext context) {
print("MyContainer 빌드됨");
return Container(
height: 20,
color: Colors.blue,
);
}
}
2.
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
home: HomePage(),
);
}
}
class HomePage extends StatefulWidget {
@override
State<HomePage> createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
int num = 1;
@override
Widget build(BuildContext context) {
//나 그려짐 나오면 전체가 다시 그려진 것이다.
print("나그려짐");
//자식이 있으면 자식의 크기만큼 작아지고 자식이 없으면 맥스 크기로 켜진다!
return Container(
color: Colors.yellow,
child: Padding(
padding: const EdgeInsets.all(20.0),
child: Column(
children: [
Expanded(
child: Container(
color: Colors.red,
child: Align(
child: Text(
"${num}",
style: TextStyle(
color: Colors.white,
fontWeight: FontWeight.bold,
fontSize: 100,
decoration: TextDecoration.none),
),
),
),
),
Expanded(
child: Container(
color: Colors.blue,
child: Align(
child: ElevatedButton(
style:
ElevatedButton.styleFrom(backgroundColor: Colors.red),
onPressed: () {
num++;
setState(() {});
},
child: Text(
"증가",
style: TextStyle(
color: Colors.white,
fontWeight: FontWeight.bold,
fontSize: 100,
),
),
),
),
),
),
],
),
),
);
}
}
3.
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
home: HomePage(),
);
}
}
class HomePage extends StatefulWidget {
@override
State<HomePage> createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
// 1. 상태
int num = 1;
// 2. 행위
void add() {
num++;
setState(() {});
}
@override
Widget build(BuildContext context) {
print("나그려짐");
return Container(
color: Colors.yellow,
child: Padding(
padding: const EdgeInsets.all(20.0),
child: Column(
children: [
Header(num: num),
Bottom(add: add),
],
),
),
);
}
}
class Bottom extends StatelessWidget {
final add;
Bottom({required this.add});
@override
Widget build(BuildContext context) {
return Expanded(
child: Container(
color: Colors.blue,
child: Align(
child: ElevatedButton(
style: ElevatedButton.styleFrom(backgroundColor: Colors.red),
onPressed: () {
add();
},
child: Text(
"증가",
style: TextStyle(
color: Colors.white,
fontWeight: FontWeight.bold,
fontSize: 100,
),
),
),
),
),
);
}
}
class Header extends StatelessWidget {
const Header({
super.key,
required this.num,
});
final int num;
@override
Widget build(BuildContext context) {
return Expanded(
child: Container(
color: Colors.red,
child: Align(
child: Text(
"${num}",
style: TextStyle(
color: Colors.white,
fontWeight: FontWeight.bold,
fontSize: 100,
decoration: TextDecoration.none),
),
),
),
);
}
}
4.
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
home: HomePage(),
);
}
}
class HomePage extends StatefulWidget {
//StatefulWidget 상태와 행위를 가질 수 있다.
//부모의 영역을 다시 시작하면 자식들도 다시 그려진다.
@override
State<HomePage> createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
// 1. 상태
int num = 1;
// 2. 행위
void add() {
num++;
setState(() {});
}
@override
Widget build(BuildContext context) {
print("나그려짐");
return Container(
color: Colors.yellow,
child: Padding(
padding: const EdgeInsets.all(20.0),
child: Column(
children: [
Header(num: num),
Bottom(add: add),
],
),
),
);
}
}
class Bottom extends StatelessWidget {
final add;
Bottom({required this.add});
@override
Widget build(BuildContext context) {
print("Botton 다시 그려짐");
return Expanded(
child: Container(
color: Colors.blue,
child: Align(
child: ElevatedButton(
style: ElevatedButton.styleFrom(backgroundColor: Colors.red),
onPressed: () {
add();
},
child: Text(
"증가",
style: TextStyle(
color: Colors.white,
fontWeight: FontWeight.bold,
fontSize: 100,
),
),
),
),
),
);
}
}
class Header extends StatelessWidget {
const Header({
super.key,
required this.num,
});
final int num;
@override
Widget build(BuildContext context) {
print("Header 다시 그려짐");
return Expanded(
child: Container(
color: Colors.red,
child: Align(
child: Text(
"${num}",
style: TextStyle(
color: Colors.white,
fontWeight: FontWeight.bold,
fontSize: 100,
decoration: TextDecoration.none),
),
),
),
);
}
}
5.
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
home: HomePage(),
);
}
}
class HomePage extends StatelessWidget {
const HomePage({super.key});
@override
Widget build(BuildContext context) {
print("HomePage 다시 그려짐");
return Container(
color: Colors.yellow,
child: Padding(
padding: const EdgeInsets.all(20.0),
child: Column(
children: [
Header(),
Bottom(),
],
),
),
);
}
}
class Bottom extends StatelessWidget {
@override
Widget build(BuildContext context) {
print("Bottom 다시 그려짐");
return Expanded(
child: Container(
color: Colors.blue,
),
);
}
}
class Header extends StatefulWidget {
@override
State<Header> createState() => _HeaderState();
}
class _HeaderState extends State<Header> {
int num = 1;
void add() {
num++;
setState(() {});
}
@override
Widget build(BuildContext context) {
print("Header 다시 그려짐");
return Expanded(
child: Container(
color: Colors.red,
child: Align(
child: Column(
children: [
Text(
"${num}",
style: TextStyle(
color: Colors.white,
fontWeight: FontWeight.bold,
fontSize: 100,
decoration: TextDecoration.none),
),
ElevatedButton(
onPressed: () {
add();
},
child: Text("증가"))
],
),
),
),
);
}
}

6. 과제 : 상태관리 HomePage(StatefulWidget)에서 (StatelessWidget)로 바꾸고 Father로 컨텍스트 분리해서 Top과 Bottom만 그림 그려보기!
1. Before 상태관리 (Father X)
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
home: HomePage(),
);
}
}
// 1. Father 클래스 생성 - SF 만들기
// 2. Father 클래스가
class HomePage extends StatefulWidget {
@override
State<HomePage> createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
int num = 1;
void add() {
num++;
setState(() {});
}
@override
Widget build(BuildContext context) {
print("HomePage");
return Container(
color: Colors.yellow,
child: Padding(
padding: const EdgeInsets.all(20.0),
child: Column(
children: [
Header(),
Expanded(
child: Top(num: num),
),
Expanded(
child: Bottom(add: add),
),
],
),
),
);
}
}
class Header extends StatelessWidget {
const Header({
super.key,
});
@override
Widget build(BuildContext context) {
print("Header");
return Container(
color: Colors.green,
height: 200,
);
}
}
class Bottom extends StatelessWidget {
// 행위
Function add;
Bottom({required this.add});
@override
Widget build(BuildContext context) {
print("Bottom");
return Container(
color: Colors.blue,
child: Align(
child: ElevatedButton(
style: ElevatedButton.styleFrom(backgroundColor: Colors.red),
onPressed: () {
add();
},
child: Text(
"증가",
style: TextStyle(
color: Colors.white,
fontWeight: FontWeight.bold,
fontSize: 100,
),
),
),
),
);
}
}
class Top extends StatelessWidget {
const Top({
super.key,
required this.num,
});
final int num;
@override
Widget build(BuildContext context) {
print("Top");
return Container(
color: Colors.red,
child: Align(
child: Text(
"${num}",
style: TextStyle(
color: Colors.white,
fontWeight: FontWeight.bold,
fontSize: 100,
decoration: TextDecoration.none),
),
),
);
}
}
2. After 상태관리 (Father O)
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
home: HomePage(),
);
}
}
class HomePage extends StatelessWidget {
const HomePage({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
print("HomePage 그러짐");
return Container(
color: Colors.yellow,
child: Padding(
padding: const EdgeInsets.all(20.0),
child: Column(
children: [
Header(),
Expanded(
child: Father(),
),
],
),
),
);
}
}
class Father extends StatefulWidget {
@override
State<Father> createState() => _FatherState();
}
class _FatherState extends State<Father> {
int num = 1;
void add() {
setState(() {
num++;
});
}
@override
Widget build(BuildContext context) {
print("Father 그려짐");
return Column(
children: [
Expanded(
child: Top(num: num),
),
Expanded(
child: Bottom(
add: add,
),
),
],
);
}
}
class Header extends StatelessWidget {
const Header({
super.key,
});
@override
Widget build(BuildContext context) {
print("header");
return Container(
color: Colors.green,
height: 200,
);
}
}
class Top extends StatelessWidget {
final int num;
const Top({Key? key, required this.num}) : super(key: key);
@override
Widget build(BuildContext context) {
print("Top 그려짐");
return Container(
color: Colors.red,
child: Center(
child: Text(
'$num',
style: TextStyle(
color: Colors.white,
fontWeight: FontWeight.bold,
fontSize: 100,
decoration: TextDecoration.none),
),
),
);
}
}
// Bottom 위젯: 버튼을 눌러 add 함수를 호출해 상태를 변경하는 역할
class Bottom extends StatelessWidget {
final VoidCallback add;
const Bottom({Key? key, required this.add}) : super(key: key);
@override
Widget build(BuildContext context) {
print("Bottom 그려짐");
return Container(
color: Colors.blue,
child: Center(
child: ElevatedButton(
style: ElevatedButton.styleFrom(backgroundColor: Colors.red),
onPressed: add,
child: Text(
"증가",
style: TextStyle(
color: Colors.white,
fontWeight: FontWeight.bold,
fontSize: 100,
),
),
),
),
);
}
}
Share article