StatefulWidget의 생명주기 메서드
createState()
class MyWidget extends StatefulWidget {
@override
_MyWidgetState createState() => _MyWidgetState(); // 가장 먼저 호출
}
initState()
class _MyWidgetState extends State<MyWidget> {
late StreamSubscription _subscription;
@override
void initState() {
super.initState(); // 반드시 super 호출
// 초기화 작업 수행
_subscription = Stream.periodic(Duration(seconds: 1))
.listen((data) => print('Stream data: $data'));
}
}
didChangeDependencies()
class _MyWidgetState extends State<MyWidget> {
ThemeData? _theme;
@override
void didChangeDependencies() {
super.didChangeDependencies();
// 상위 위젯의 데이터 의존성 변경 시 호출
_theme = Theme.of(context); // InheritedWidget 데이터 접근
}
}
build()
class _MyWidgetState extends State<MyWidget> {
@override
Widget build(BuildContext context) {
return Container(
child: Text('Widget Content'),
);
}
}
didUpdateWidget()
class _MyWidgetState extends State<MyWidget> {
@override
void didUpdateWidget(MyWidget oldWidget) {
super.didUpdateWidget(oldWidget);
// 위젯이 업데이트될 때 호출
if (widget.someProperty != oldWidget.someProperty) {
// 속성 변경에 따른 처리
}
}
}
dispose()
class _MyWidgetState extends State<MyWidget> {
late StreamSubscription _subscription;
@override
void dispose() {
// 리소스 해제
_subscription.cancel();
super.dispose(); // 반드시 마지막에 super 호출
}
}
생명주기 단계별 주의사항
initState
- super.initState() 반드시 먼저 호출
- context 사용 불가 (didChangeDependencies에서 사용)
- 비동기 작업 시작 가능
- 한 번만 호출됨
didChangeDependencies
- InheritedWidget 데이터 접근
- 여러 번 호출될 수 있음
- 상위 위젯의 데이터 변경 시 호출
build
- 순수 함수여야 함
- 상태 변경 금지 (setState 호출 금지)
- 가능한 가벼운 연산만 수행
dispose
- 리소스 해제 필수
- super.dispose() 마지막에 호출
- mounted 체크 후 setState 호출
일반적인 실수와 해결방법
메모리 누수 방지
class _MyWidgetState extends State<MyWidget> {
StreamSubscription? _subscription;
@override
void initState() {
super.initState();
_subscription = Stream.periodic(Duration(seconds: 1))
.listen((data) {
if (!mounted) return; // mounted 체크
setState(() {
// 상태 업데이트
});
});
}
@override
void dispose() {
_subscription?.cancel();
super.dispose();
}
}
비동기 작업 처리
class _MyWidgetState extends State<MyWidget> {
@override
void initState() {
super.initState();
_loadData();
}
Future<void> _loadData() async {
try {
await Future.delayed(Duration(seconds: 2));
if (!mounted) return;
setState(() {
// 상태 업데이트
});
} catch (e) {
print('Error: $e');
}
}
}
Context 사용
class _MyWidgetState extends State<MyWidget> {
@override
void initState() {
super.initState();
// Error: context 사용 불가
// Theme.of(context);
}
@override
void didChangeDependencies() {
super.didChangeDependencies();
// OK: context 사용 가능
final theme = Theme.of(context);
}
}
마치며
위젯의 생명주기를 잘 이해하고 적절히 활용하면 메모리 누수를 방지하고 효율적인 상태 관리가 가능합니다. 특히 dispose() 메서드에서의 리소스 해제와 비동기 작업 시의 mounted 체크는 매우 중요합니다.
'Language > Flutter' 카테고리의 다른 글
[Flutter] 앱 아이콘 변경 (0) | 2024.11.22 |
---|---|
[Flutter] 앱 이름 변경 (0) | 2024.11.21 |
[Dart] fold() 메소드 (0) | 2024.11.19 |
[Flutter] 상태 관리 기초 - setState (0) | 2024.11.18 |
[Dart] Spread 연산자(...) (0) | 2024.11.17 |