플러터는 상태를 가지고 그림을 그린다.
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)),
const 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,
);
}
}
이렇게하면 new를 다시 안한다. new가 두번안된거 랜더링은 계속 다시된다.
성능적으로 new를 한번만 하니 좋다.
컨텍스트 분리가 안되어있는 예제
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 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,
),
),
),
),
),
),
],
),
),
);
}
}
문제1 .컨텍스트를 분리하지 않으면 화면전체가 그려진다.
문제2. 컨텍스트를 분리하면 해당컨텍스트만 분리는 가능하다 다만 이렇게해도 아직 전체가 stateful하다
수정한 예제
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 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("바텀다시그려짐");
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("헤더다시그려짐");
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),
),
),
),
);
}
}
부모가 stateful 이고 상태와 행위를 다 가지고 있는 예제

컨텍스트를 분리하여, 상태가 변경되는 부분만 sf로 만든다.
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("증가"))
],
),
),
),
);
}
}
공통부모를 둔 stateful 부분로딩가능
.

그림을 그리다 보면, 상태의 화면과 행위의 화면이 다를때 가 있다.(가장 가까운 공통부모를 sf로 두고 상태와 행위를 전달한다.)
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("홈페이지");
return Container(
color: Colors.yellow,
child: Padding(
padding: const EdgeInsets.all(20.0),
child: Column(
children: [
Header(),
Expanded(
child: Father(),
),
],
),
),
);
}
}
class Header extends StatelessWidget {
const Header({
super.key,
});
@override
Widget build(BuildContext context) {
print("헤더 페이지");
return Container(
color: Colors.green,
height: 200,
);
}
}
class Father extends StatefulWidget {
@override
State<StatefulWidget> createState() => _FatherState();
}
class _FatherState extends State<Father>{
int num = 1;
void add(){
num++;
setState(() {});
}
@override
Widget build(BuildContext context) {
// TODO: implement build
return Column(
children: [
Expanded(child: Top(num: num)),
Expanded(child: Bottom(add: add)),
],
);
}
}
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),
),
),
);
}
}
이렇게하면
로그가
홈페이지
헤더 페이지
Top 페이지
Bottom 페이지
Top 페이지
Bottom 페이지
Top 페이지
Bottom 페이지
이런식으로 처음에는 4개의 prinf가 호출되지만 클릭을 하여 추가버튼을 누르며 top과 bottom만 stateful하게 작동하는 걸 확인할 수있다.
옵저버 패턴
컨텍스트가 복잡하면 부모를 위치시키기 힘든경우가 생긴데 그래서 나온게
옵저버 패턴
위젯에서 분리시킨 상태 클래스를 두어서 만든다
Share article