플러터와 Stateful Widget
2023. 10. 31. 16:03ㆍFrontend/Dart&Flutter
Stateless vs. Stateful
- Stateless Widget : build 메서드를 통해 단지 UI를 출력함.
- Stateful Widget : 상태에 따라 변화하는 데이터를 생각함. 데이터가 변화될때마다 UI가 변경됨. 위젯에 데이터 저장후 실시간으로 데이터 변화를 볼 수 있음.
- 상태가 없는 위젯 그 자체
- 위젯의 상태로 state는 위젯에 들어갈 데이터와 UI를 넣는 곳. 데이터가 변경되면 해당 위젯의 UI도 변경됨.
Stateful Widget을 만드는 법
- st만 작성시 stateless 또는 stateful 위젯을 선택할 수 있음
- stateless widget에서 staeful 위젯으로 변경. 코드 액션 : convert to stateful widget
Stateful Widget의 특성
- stateful widget의 데이터는 단지 dart 클래스 프로퍼티일 뿐.
class App extends StatefulWidget {
// extend됨
const App({super.key});
@override
State<App> createState() => _AppState();
}
class _AppState extends State<App> {
// State 가 변경시 UI 가 변경됨.
@override
Widget build(BuildContext context) {
- 예제
class _AppState extends State<App> {
int counter = 0;
void onClicked() {
setState(() {
counter = counter + 1;
});
}
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
backgroundColor: const Color(0xFFF4EDDB),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Text('Click Count', style: TextStyle(fontSize: 30)),
Text('$counter', style: const TextStyle(fontSize: 30)),
IconButton(
iconSize: 40,
onPressed: onClicked,
icon: const Icon(Icons.add_box_rounded))
]))));
}

setState 함수
- state 클래스에게 데이터가 변경되었다고 알림. setState함수를 통하지 않고는 build 메서드가 수행되지 않음. 새로운 데이터와 함께 build 메서드를 호출함.
// setState 안에서 변화시킴 (추천)
void onClicked() {
setState(() {
counter = counter + 1;
});
}
// 다른 방식의 사용법 : 데이터의 변화를 setState 안에 무조건 넣을 필요는 없음.
void onClicked() {
counter = counter + 1;
setState(() {});
}
- 예제 : 숫자 배열 표시하기
class App extends StatefulWidget {
const App({super.key});
@override
State<App> createState() => _AppState();
}
class _AppState extends State<App> {
List<int> numbers = [];
void onClicked() {
setState(() {
numbers.add(numbers.length);
});
}
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
backgroundColor: const Color(0xFFF4EDDB),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Text('Click Count', style: TextStyle(fontSize: 30)),
for (var n in numbers) Text('$n'),
IconButton(
iconSize: 40,
onPressed: onClicked,
icon: const Icon(Icons.add_box_rounded))
]))));
}
}

BuildContext
- 위젯 트리
- App 루트 아래로 자식들을 가짐.
- 자식요소가 부모 요소(MaterialApp)에 접근
- BuildContext의 context : Text 이전에 있는 모든 상위 요소에 대한 정보. 부모 요소들의 모든 정보를 담고 있음. context를 통해 먼 곳의 요소에 접근할 수 있음.
- theme : default style. 앱의 스타일을 한 곳에서 다룰 수 있음. 일일이 복붙, 타이핑하지 않아도 됨.
StatefulWidget의 라이프사이클
- initState : build 이전에 호출. 변수를 초기화하고 API 업데이트를 구독할 수 있도록 함. 부모요소에 의존하는 데이터를 초기화하기 위해 사용. 단 한번만 호출됨. build 보다 먼저 호출되어야함.
@override
void initState() {
super.initState();
}
- build : 위젯에서 UI를 만듦
- dispose : 위젯이 제거될 때. 이벤트 리스너 같은 것들을 구독 취소하는 것. 위젯이 스크린에서 제거될 때 호출되는 메서드. api 업데이트나 이벤트 리스터로부터 구독을 취소하거나 form의 리스터로부터 벗어나고 싶을 때. 취소하고 싶을 때. 위젯트리에서 제거되기 전에 무언가를 취소하고 싶을 때
- 예제
import 'package:flutter/material.dart';
void main() {
runApp(const App());
}
class App extends StatefulWidget {
const App({super.key});
@override
State<App> createState() => _AppState();
}
class _AppState extends State<App> {
bool showTitle = true;
void toggleTitle() {
setState(() {
showTitle = !showTitle;
});
}
@override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData(
textTheme: const TextTheme(
titleLarge: TextStyle(color: Colors.red),
),
),
home: Scaffold(
backgroundColor: const Color(0xFFF4EDDB),
body: Center(
child: Column(mainAxisAlignment: MainAxisAlignment.center, children: [
showTitle ? const MyLargeTitle() : const Text('nothing'),
IconButton(
onPressed: toggleTitle, icon: const Icon(Icons.remove_red_eye))
]),
),
),
);
}
}
class MyLargeTitle extends StatefulWidget {
const MyLargeTitle({
super.key,
});
@override
State<MyLargeTitle> createState() => _MyLargeTitleState();
}
class _MyLargeTitleState extends State<MyLargeTitle> {
@override
void initState() {
super.initState();
print('initState!');
}
@override
void dispose() {
super.dispose();
print('dispose!');
}
@override
Widget build(BuildContext context) {
print('build!');
return Text('My Large Title',
style: TextStyle(
fontSize: 30,
color: Theme.of(context).textTheme.titleLarge?.color));
}
}

flutter: initState!
flutter: build!

dispose!
// 위젯 트리에서 제거됨'Frontend > Dart&Flutter' 카테고리의 다른 글
| Data Fetching과 패키지 설치 (0) | 2023.12.15 |
|---|---|
| 플러터 화면구성 (1) | 2023.10.31 |
| 플러터란? 프로젝트 시작하기 (1) | 2023.10.31 |
| Dart 기초 (Functions, Classes) (0) | 2023.08.15 |
| Dart 기초 (Variables, DataType) (1) | 2023.04.21 |