Study Record

[Flutter] StatelessWidget / StatefulWidget 생명 주기 본문

Flutter

[Flutter] StatelessWidget / StatefulWidget 생명 주기

초코초코초코 2023. 1. 30. 01:10
728x90

✍ 클래스 생성 단축키

  • stful : StatefulWidget 생성 단축키
  • stless : StatelessWidget 생성 단축키

 

✍ StatelesssWidget

상태를 관리할 수 없는 위젯이다.

  • Constructor 로 생성된 후 바로 build 함수가 실행된다.
  • 변경이 필요하면 새로운 위젯을 만든다. (색 변경 등)
  • 하나의 StatelessWidget은 라이프사이클동안 단 한 번만 build 함수를 실행한다.

 

※ 생명 주기

 

아래의 코드와 같이 StatelessWidget 을 상속받으면 StatelessWidget 을 생성할 수 있다. build() 함수의 return 값으로 생성하고자 하는 위젯을 리턴하면 된다.

class HomeScreen extends StatelessWidget{
  String imgPath;
  HomeScreen({required this.imgPath});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        body: Center(
            child: Image.asset(imgPath)
        )
    );
  }
}

/**
 * main 함수에서 StatelessWidget 사용 예시 
 */
void main() {
  runApp(
    MaterialApp(
      debugShowCheckedModeBanner: false,
      home: HomeScreen(imgPath: "asset/img/free_hart_img.png"),
    ),
  );
}

예시로 만든 HomeScreen 클래스(위젯)은 한 번 생성되면 build() 함수가 생성될 당시 한 번만 실행되기 때문에 이미지 값(asset/img/logo.png)을 변경할 수 없다. imgPath 를 직접 변경한다고 해도 build() 를 다시 호출할 수 없기 때문에 이미지를 변경할 수 없다. 이렇듯 StatelessWidget 은 새로 값이 변경되어야 한다면 변경된 값의 새로운 위젯을 만든다.

 

+  Hot reload 는 빌드함수에서 리턴하는 위젯의 변경시 사용할 수 있다.

 

✍ StatefulWidget 

상태를 관리할 수 있는 위젯이다. 위젯의 상태를 관리하는 State 클래스가 사용된다.

 

※ 생명 주기

기본

 기본적으로 StatefulWidget 의 생명 주기는 위의 그림과 같다. 위젯이 정상적으로 생성되면 Clean 상태까지 유지되고 위젯(StatefulWidget) 이 삭제된다고 무조건 연결된 State 가 deactivate() → dispose() 과정을 거치지는 않는다.

class StatefulTestHomeScreen extends StatefulWidget {
  const StatefulTestHomeScreen({Key? key}) : super(key: key);

  @override
  State<StatefulTestHomeScreen> createState() => _StatefulTestHomeScreenState();
}

class _StatefulTestHomeScreenState extends State<StatefulTestHomeScreen> {

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: SafeArea(
        child: Column(
        	...
        ),
      ),
    );
  }
}

 

 

StatefulWidget 가 삭제되고 State 가 deactivate() → dispose() 과정을 거치지는 않는 경우가 있는데 파라미터 값이 바뀌었을 경우이다. 예를 들어, 기존의 위젯에서 색상을 바꾸고 싶다면 새로운 위젯이 생성되는데 여기서 StatelfulWidget 이 삭제되고 새로 생성될 때 State 는 삭제되지 않고 새롭게 생성되는 StatefulWidget 에 연결된다. 과정을 그림으로 보면 다음과 같다.

파라미터 값이 바뀌었을 경우

 연결되는 과정에서 didUpdateWidget() 가 불리고 build() 함수가 불리면서 위젯이 새로 생성된다.

 

 

StatefulWidget 을 사용하는 이유라고도 할 수 있는 State 클래스의 setState() 함수가 있는데 이 함수를 사용하면 StatefulWidget 을 삭제하지 않고 값을 바꿀 수 있다. 생명 주기의 과정은 다음과 같다.

setState() 과정

 

예를 들어 "위젯 색깔 바꾸기" 버튼을 누르면 중앙에 있는 위젯의 바탕색이 바뀌는 간단한 앱이 있으면,

다음과 같이 StatefulTestHomeScreen 클래스를 작성할 수 있을 것이다.

class StatefulTestHomeScreen extends StatefulWidget {
  const StatefulTestHomeScreen({Key? key}) : super(key: key);

  @override
  State<StatefulTestHomeScreen> createState() => _StatefulTestHomeScreenState();
}

class _StatefulTestHomeScreenState extends State<StatefulTestHomeScreen> {
  Color color = Colors.orange;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: SafeArea(
        child: Column(
          children: [
            Expanded(
              flex: 1,
              child: Center(
                child: CustomContainer(color: color)
              ),
            ),
            Container(
              margin: const EdgeInsets.all(15.0),
              color: Colors.red,
              child: TextButton(
                onPressed: () {
                  setState(() {
                    color = (color == Colors.orange ? Colors.lightBlue : Colors.orange);
                  });
                },
                child: Container(
                  width: MediaQuery.of(context).size.width,
                  child: const Center(
                    child: Text(
                      "위젯 색깔 바꾸기",
                      style: TextStyle(color: Colors.white),
                    ),
                  ),
                ),
              ),
            ),
          ],
        ),
      ),
    );
  }
}

"위젯 색깔 바꾸기" 버튼을 누르면 StatefulTestHomeScreenState 의 setState() 함수가 실행되고 그때 위젯의 색상을 결정짓는 변수(color)를 변경하면 setState() → build() 함수가 불리면서 다시 CustomContainerWidget 이 바뀐 색상으로 새로 생성될 것이다.

 

 

여기서 CustomContainerWidget 을 StatefulWidget 으로도 작성할 수 있고 StatelessWidget 으로도 작성할 수 있다.

 

1. StatefulWidget 으로 작성된 경우

class CustomContainer extends StatefulWidget {
  final Color color;
  CustomContainer({required this.color, Key? key}) : super(key: key)
  
  @override
  State<CustomContainer> createState() {
    return _CustomContainerState();
  }
}

class _CustomContainerState extends State<CustomContainer> {
  @override
  Widget build(BuildContext context) {
    print("_CustomContainerState build  실행");
    return Container(
      width: 50.0,
      height: 50.0,
      color: widget.color,
    );
  }
}

StatefulTestHomeScreenState 의 setState() 함수가 실행되고 StatefulTestHomeScreenState 의 build() 함수가 불려 다시 CustomContainer 가 새로 생성되는 경우는 파라미터 값이 바뀌었을 경우 해당되며 과정은

 

StatefulTestHomeScreenState setState() StatefulTestHomeScreenState build() 

CustomContainer Constructor → CustomContainerState didUpdateWidget() → CustomContainerState build() 

 

가 될 것이다. CustomContainerState build() 과정에서 위젯의 색상이 widget.color 로 되어있는데 이 의미는 현재 State 와 연결된 StatefulWidget 의 color 값을 의미한다.

 

따라서 StatefulTestHomeScreenState setState() 과정에서 변경한 color 값으로 StatefulTestHomeScreenState build() 에서 CustomContainer(color: color) 가 실행되면서 CustomContainer 클래스가 생성되고 연결된 CustomContainerState 의 build() 가 실행될 때 변경된 CustomContainer.color 값으로 위젯이 생성된다.

 

 

2. StatelessWidget 으로 작성된 경우

class CustomContainer extends StatelessWidget {
  final Color color;
  CustomContainer({required this.color, Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Container(
      width: 50.0,
      height: 50.0,
      color: color,
    );
  }
}

 

마찬가지로 StatefulTestHomeScreenState 의 setState() 함수가 실행된 후 StatefulTestHomeScreenState 의 build() 함수가 불려 다시 CustomContainer 가 새로 생성된다. StatelessWidget 은 StatefulWidget 와 달리 별다른 과정이 없고 새로운 위젯이 생성된다. 따라서 과정은 다음과 같다.

 

StatefulTestHomeScreenState setState()  StatefulTestHomeScreenState build() 

 CustomContainer Constructor → CustomContainer build()

 

StatefulTestHomeScreenState setState() 과정에서 변경한 color 값으로 StatefulTestHomeScreenState build() 에서 CustomContainer(color: color) 가 실행된다.

 

728x90