본문 바로가기
모바일 공부/Flutter

StatelessWidget,StatefulWidget 알아보기

by chogigang 2024. 1. 5.

플러터를 보면 항상 

class MyApp extends StatelessWidget {

 

class DiceRoller extends StatefulWidget {

 

 

이런걸 상속 받는걸 볼수 있습니다. 

 

이 위잿들은 정보를 받고 플러터가 어떻게 반응을 하는지 결정을 하는 위젯들입니다.

 

 

StatelessWidget

StatelessWidget은 상태가 없는 위젯으로, 한 번 그려지면 변하지 않는 UI를 표현하는 데 사용됩니다. 이 위젯은 일반적으로 변하지 않는 정적인 콘텐츠를 표시할 때 유용합니다. 예를 들어, 화면에 특정한 로고, 텍스트 레이블 등을 표시할 때 StatelessWidget을 사용할 수 있습니다.  무언가 버튼이나 터치를 했을때 변화가 필요한것이 필요하다면 StatelessWidget 은 적합하지 않다고 생각합니다

 

 

 

StatefulWidget

StatefulWidget은 동적인 UI를 표현하는 데 사용됩니다. 이 위젯은 상태를 가지고 있어서 사용자 인터랙션 또는 외부 이벤트에 따라 UI가 변경될 수 있습니다. 예를 들어, 사용자가 버튼을 클릭하면 해당 버튼의 색상을 변경하는 등의 동적인 행위를 구현할 때 StatefulWidget을 활용할 수 있습니다. 허나 화면 변화가 필요없는 화면들은 굳이 메모리를 더 사용하면서 사용할 필요가 없어집니다.

 

간단하게 더 요약하자면 

 

1. Widget이 빌드 될 때 동기적으로 읽을 수 있어진다.

2. Widget의 생명주기동안 변경될 수 있어진다.

 

 

이전글 부터 계속 이어지던 예제들을 이어서 붙여봅시다.

 

주사위 굴리기 예제 입니다 전체 코드를 받고 싶으시면 https://github.com/chogigang/flutter_dice  로가셔서 받으시면 됩니다. 

그중 하나의 코드 입니다 

dice_roller.dart

import 'package:flutter/material.dart';
import 'dart:math';

final randomizer = Random().nextInt(6) + 1;

class DiceRoller extends StatefulWidget {
  const DiceRoller({
    super.key,
  });
  @override
  State<DiceRoller> createState() {
    return _DiceRollerState();
  }
}

class _DiceRollerState extends State<DiceRoller> {
  var activeDiceImage = 'assets/images/dice-$randomizer.png';

  void rollDice() {
    setState(() {
      final randomizer = Random().nextInt(6) + 1;
      activeDiceImage = 'assets/images/dice-$randomizer.png';
    });
  }

  @override
  Widget build(context) {
    return Column(
      mainAxisSize: MainAxisSize.min, // 주축은 수직 축
      children: [
        Image.asset(
          activeDiceImage,
          width: 200,
        ),
        const SizedBox(
          height: 20,
        ),
        TextButton(
          onPressed: rollDice,
          style: TextButton.styleFrom(
              // padding: const EdgeInsets.only(
              //   top: 20,
              // ),
              foregroundColor: Colors.white, ////foregroundColor 전경색, 도구색
              textStyle: const TextStyle(
                fontSize: 28,
              )),
          child: const Text('주사위 돌리기'),
        )
      ],
    );
  }
}

 

주사위를 굴리기 버튼을 눌렀을때 이미지가 변경이 되면서 주사위를 굴릴수 있습니다. 이러한 동적으로 필요할때 StatefulWidget 를 사용합니다..

 

 

그럼 이제  StatefulWidget 사용할때의 생명주기를 주의 해야하기때문에 생명주기를 작성해봅시다.

 

 

flutter 의 생명주기

플러터 앱에서는 위젯의 생성부터 파기까지의 위젯의 생명주기가 관리 되어지고 있고, 생명주기의 특정 시점에서 특정 메소드가 호출되어집니다. 이러한 라이프사이클의 상태를 이해함으로써 위젯의 정교한 제어가 가능해집니다. 위젯을 만들 때 우리가 잘 인식하지 않고 사용하고 있는 build 메소드나 initState메소드 역시 라이프사이클과 관련된 메소드 입니다.

 

생명주기를 잘 생각해놓으면 이점들을 생각해봅시다. 

 

  1. UI 상태 관리: StatefulWidget은 상태를 가지는 위젯으로, 사용자 인터페이스의 상태를 관리하는 데 사용됩니다.
  2. 위젯이 화면에 표시되고 변경될 때마다 생명주기 메서드가 호출되며, 이를 통해 화면의 상태를 업데이트하고 반응적인 UI를 구현할 수 있습니다.
  3. 상태 변경 감지: StatefulWidget의 생명주기 메서드를 이용하면 상태의 변화를 감지하고, 이에 따라 필요한 작업을 수행할 수 있습니다.
  4. 예를 들어, 사용자의 입력에 따라 화면을 업데이트하거나 데이터를 로드하는 등의 작업을 수행할 수 있습니다.
  5. 자원 관리: 애플리케이션에서 사용되는 자원(메모리, 네트워크 등)을 효율적으로 관리하려면 StatefulWidget의 생명주기를 이해해야 합니다.
  6. 필요한 자원을 적절하게 할당하고 해제하는 작업을 생명주기 메서드 내에서 수행할 수 있습니다.
  7. 문제 해결 및 디버깅: 애플리케이션에서 예기치 않은 동작이나 버그가 발생했을 때 StatefulWidget의 생명주기를 분석하면 문제의 원인을 찾아낼 수 있습니다.
  8. 특정 생명주기 단계에서 발생하는 문제를 파악하여 수정할 수 있습니다.
  9. 성능 최적화: 상태 변화에 따른 화면 업데이트를 효율적으로 처리하여 성능을 최적화할 수 있습니다.
  10. 예를 들어, 불필요한 업데이트를 방지하거나 비용이 큰 작업을 최소화할 수 있습니다.
  11. 동작 예측: StatefulWidget의 생명주기를 이해하면 위젯의 동작을 예측할 수 있습니다.
  12. 화면이 언제 업데이트되는지, 어떤 순서로 메서드가 호출되는지 등을 알고 있으면 개발자가 의도한 동작을 보다 정확하게 제어할 수 있습니다.

  애플리케이션의 UI 상태 관리, 상태 변경 감지, 자원 관리, 문제 해결 및 디버깅, 성능 최적화, 동작 예측 등

다양한 측면에서 개발과 유지보수의 품질을 높일 수 있기 때문입니다.

 

 

# 출처 :https://devocean.sk.com/blog/techBoardDetail.do?ID=165205&boardType=techBlog

 

라이프 사이클(lifecycle) 개요

 

그럼 이제 이 개요도에 있는  함수 몇개를 간단하게 설명 해봅시다.

 

 

1. createState()

createState() 메서드는 StatefulWidget의 상태를 생성하는 역할을 합니다. 이 메서드는 한 번만 호출되며, 상태 객체가 생성됩니다. 상태 객체는 StatefulWidget의 생명주기와 함께 동작하여 상태를 유지하고 관리합니다.

 

@override
State createState() => _MyWidgetState();

 

2. initState()

initState() 메서드는 StatefulWidget의 상태가 생성된 직후에 호출됩니다. 이 메서드는 초기 설정이나 데이터 로딩과 같은 작업을 수행하기에 이상적인 위치입니다. 상태가 최초로 생성되었을 때 한 번 호출되며, 뒤이어 딱 한 번 호출됩니다

@override
void initState() {
  super.initState();
  // 초기 설정 작업 수행
}

3. didChangeDependencies()

didChangeDependencies() 메서드는 StatefulWidget의 상태가 의존성이 변경될 때 호출됩니다. 예를 들어, 부모 위젯에서 데이터가 변경되었을 때, 해당 메서드가 호출되어 상태를 업데이트할 수 있습니다.

@override
void didChangeDependencies() {
  super.didChangeDependencies();
  // 의존성이 변경되었을 때 수행할 작업
}

4. build()

build() 메서드는 위젯의 UI를 구성하는 역할을 합니다. 이 메서드는 상태가 변경될 때마다 호출되어 UI를 업데이트합니다.

@override
Widget build(BuildContext context) {
  // UI를 구성하는 작업
  return Container();
}

5. didUpdateWidget()

didUpdateWidget() 메서드는 위젯의 설정이나 속성이 변경될 때 호출됩니다. 이 메서드를 통해 새로운 속성을 기반으로 상태를 업데이트할 수 있습니다.

@override
void didUpdateWidget(MyWidget oldWidget) {
  super.didUpdateWidget(oldWidget);
  // 위젯의 설정이나 속성이 변경될 때 수행할 작업
}

6. setState()

setState() 메서드는 상태를 업데이트하고 화면을 다시 그릴 때 사용됩니다. 이 메서드를 호출하면 build() 메서드가 다시 실행되어 UI가 갱신됩니다.

void _updateState() {
  setState(() {
    // 상태를 업데이트하는 작업
  });
}

7. deactivate() 및 dispose()

deactivate()와 dispose() 메서드는 StatefulWidget이 화면에서 제거될 때 호출됩니다. deactivate()는 위젯이 활성 상태에서 비활성 상태로 전환될 때, dispose()는 위젯이 완전히 제거될 때 호출됩니다.

@override
void deactivate() {
  // 비활성 상태로 전환될 때 수행할 작업
  super.deactivate();
}

@override
void dispose() {
  // 위젯이 완전히 제거될 때 수행할 작업
  super.dispose();
}