
Widget Life Cycle❓
위젯이 화면에 나타나는 순간부터 화면에서 사라지는 순간까지 일어나는 일을 정의해 놓은 것
StatelessWidget일 경우에는 생성자가 처음 실행이 되고 그 다음에 빌드 함수를 실행한다. 이 걸 증명하기 위해서 코드를 작성해 보았다 프로젝트 초기화 후에 코드를 작성했다.
import 'package:flutter/material.dart';
class HomeScreen extends StatelessWidget {
const HomeScreen({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
body: HanByeulWideget(),
);
}
}
class HanByeulWideget extends StatelessWidget {
HanByeulWideget({super.key}){
print('-----생성자-----');
}
@override
Widget build(BuildContext context) {
print('-----빌드-----');
return Container(
width: 50,
height: 50,
color: Colors.red,
);
}
}
Performing hot restart...
Syncing files to device iPhone 15 Pro Max...
Restarted application in 262ms.
flutter: -----생성자-----
flutter: -----빌드-----
flutter: -----생성자-----
flutter: -----빌드-----
콘솔창을 확인해 보면 생성자가 먼저 실행되고 빌드 함수가 실행된다.
일단 StatefulWidget인 HanByeulWidget을 HomeScreen에 정의했다.
import 'package:flutter/material.dart';
class HomeScreen extends StatelessWidget {
const HomeScreen({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
body: HanByeulWidget(),
);
}
}
/*StatefulWidget*/
class HanByeulWidget extends StatefulWidget {
@override
State<HanByeulWidget> createState() => _HanByeulWidgetState();
}
/*State 클래스*/
class _HanByeulWidgetState extends State<HanByeulWidget> {
@override
Widget build(BuildContext context) {
return Container(
width: 50,
height: 50,
color: Colors.orange,
);
}
}
그리고 빌드가 되는 순서는 그냥 냅다 적어보기로 하자 왜냐면 먼 말인지 1도 모르겠기 때문이다.
HanByeulWidget
Constructor() ➡️ createState()
가장 먼저 실행되는 건 생성자이고 StatefulWidget은 무조건 creatState()함수를 정의해 주어야 한다. 이 createState()함수는 _HanByeulWidgetState 이라는 State클래스를 생성한다.
_HanByeulWidgetState
initState() ➡️ didChangeDependencies() ➡️ dirty ➡️ build() ➡️ clean ➡️ deactivate() ➡️ dispose()
❗️위젯이 생성되는 이 라이프사이클 중에서 어떤 상황에 우리가 특정 함수나 기능을 실행하고 싶을 때 실행하고 변경할 수 있도록 특정 라이프 사이클 구간에 함수를 정의해 제공한 것
initState()
State클래스에서는 constructor이야기를 하지 않고 initState()가 중요하다. State클래스가 인스턴스화 됐을 때 딱 한 번 실행되는 함수이다.
didChangeDependencies()
init() 함수에서 context를 사용하지 못하는데 didChangeDependencies() 함수에서 context를 제공한다. 그리고 여러 번 실행될 수 있다. State클래스가 의존성이 변경됐을 때 다시 실행이 된다는데 대체 먼말이냐 진짜로 하
예를 들어 Theme.of(), MediaQuery.of()같은 기능을 사용할 때 이 함수를 다시 실행할 수 있다는 것. 짜증난다 어려워서.
Dirty, Clean
클래스의 상태를 말한다. 빌드가 실행돼야 하는 상태는 Dirty, 빌드가 실행된 다음의 상태 Clean
deactivate(), dispose()
state가 삭제되고 화면에서 사라지면 deactivate(), dispose()함수가 차례로 실행된다. 위젯이 화면에서 지워졌을 때 실행된다.
SetState실행했을 때 Life Cycle
import 'package:flutter/material.dart';
class HomeScreen extends StatelessWidget {
const HomeScreen({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
body: HanByeulWidget(),
);
}
}
class HanByeulWidget extends StatefulWidget {
const HanByeulWidget({super.key});
@override
State<HanByeulWidget> createState() => _HanByeulWidgetState();
}
class _HanByeulWidgetState extends State<HanByeulWidget> {
Color color = Colors.blue;
@override
Widget build(BuildContext context) {
return GestureDetector(
onTap: (){
setState(() {
color = color == Colors.red ? Colors.blue : Colors.red;
});
},
child: Container(
width: 50,
height: 50,
color: color,
),
);
}
}
컨테이너를 누를 때 onTap() 함수가 실행된다. 라이프사이클을 살펴보자.
HanByeulWidget
Constructor() ➡️ createState()
요건 똑같
_HanByeulWidgetState
initState() ➡️ didChangeDependencies() ➡️ dirty ➡️ build() ➡️ clean
까지 처음 화면이 생성 되었을 때 실행된 후 컨테이너를 누를 때 마다 setState가 실행되도록 설계를 한 것 setState는 빌드 함수를 다시 실행시켜 state 클래스를 다시 dirty상태로 만든다. 그리고 빌드가 다시 실행되고 clean상태로 만들어 준다.
setState() ➡️ dirty ➡️ build() ➡️ clean➕ setState함수를 정의하고 안에 컬러를 바꾸는 변수의 변경은 dirty상태가 되기 직전에 일어나게 된다.
버튼을 누르면 나타나고 사라지는 박스를 구현해 보자. 여기에 작성된 코드는 모두 프로젝트 초기화 구조를 참고한다. 아래 코드는 home_screen.dart 파일 내부에 작성한다.
import 'package:flutter/material.dart';
class HomeScreen extends StatefulWidget {
const HomeScreen({super.key});
@override
State<HomeScreen> createState() => _HomeScreenState();
}
class _HomeScreenState extends State<HomeScreen> {
bool show = false;
@override
Widget build(BuildContext context) {
return Scaffold(
body: HanByeulWidget(),
);
}
}
class HanByeulWidget extends StatelessWidget {
const HanByeulWidget({super.key});
@override
Widget build(BuildContext context) {
return Container(
width: 50,
height: 50,
color: Colors.blue,
);
}
}
일단 화면에 박스를 하나 그렸다. 다음으론 박스를 가운데 정렬하고 버튼을 추가해 본다.
.
.
.
class _HomeScreenState extends State<HomeScreen> {
bool show = false;
@override
Widget build(BuildContext context) {
return Scaffold(
body: SizedBox(
width: double.infinity,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
if (show) HanByeulWidget(),
SizedBox(height: 32),
ElevatedButton(
onPressed: (){},
child: child,
),
],
),
),
);
}
}
우선 가운데 정렬은 SizedBox()와 Column()의 속성으로 레이아웃을 잡았다. 그래고 클래스 내부에 bool show = false라는 변수를 추가했다.
children: [
if (show) HanByeulWidget(),
.
.
.
],
리스트 안에서 조건문을 적용시킬 수 있다. 조건문 바로 뒤에 위젯을 작성해 준다. 이건 바로 뒤 위젯에만 해당되고 리스트 안에서만 작성할 수 있는 문법이다. 값이 false이면 위젯은 사라지고 true이면 위젯은 보이게 된다.
SizedBox(height: 32),
중간에 SizedBox() 위젯을 이용해 여백을 만들어 줄 수 있다.
ElevatedButton(onPressed: onPressed, child: child)
클릭하면 누른 부분에서 색상이 퍼져나가는 버튼이다. 이 버튼을 활용해 보자.
ElevatedButton(
onPressed: (){
setState(() {
show = !show;
});
},
child: Text('Click!'),
),
여기서 가장 중요한 점은 setState()를 넣어주어 dirty상태를 만들어 코드를 작동하게 하는 것 ! 이제 StatefullWidget의 라이프 사이클을 상세하게 알아보자! 총 3가지가 있는데 위에 2가지밖에 간단하게 정리하지 않아서 세세하게 다시 정리를 해보려고 한다.