본문 바로가기
App Programming/Flutter

[Flutter] Widget - StatefulWidget & StatelessWidget

by 젠틴 2022. 5. 6.

1. StatefulWidget과 StatelessWidget이란?

StatefulWidget이란 상태(state)를 가지는 Widget입니다.

반대로, StatelessWidget이란 상태(state)를 가지지 않는 Widget입니다.

 

* StatelessWidget도 (변경은 불가능한) 내부 State를 가지기에 엄연히 State가 있는 Widget이라고 표현하시는 분들이 있지만, Flutter 공식 문서에서는 State의 의미를 다음과 같이 정의합니다.

- Widget이 생성될 때 동기적으로 읽을 수 있을 수 있는 정보

- Widget의 생명주기 동안 변경될 수 있는 정보

즉, 읽을 수 있고 변경 가능한 정보를 State라고 정의하고 있습니다.

실제 코드에서도 Stateless Widget은 State Widget을 상속(extends)하지 않습니다.

 

그럼 상태(State)란 무엇일까요?

상태(State)의 의미를 보다 쉽게 정리해보도록 하겠습니다.

상태란 간단히 설명드리면, 현재의 데이터 값을 기억하고 있는 창고입니다.

예를 들어보겠습니다.

제작 중인 앱에서 라이트 모드와 다크 모드를 제공하고자 한다면, 2가지 모드 중 하나를 선택하고 기억할 수 있는 기능이 필요합니다. 임의의 mode라는 데이터(변수)를 생성했다고 가정해보겠습니다. 값이 참(true)이라면 라이트 모드, 거짓(false)이라면 다크 모드로 동작하도록 개발한다고 한다면, 모드를 바꿀 때마다 mode 데이터의 값은 계속 변경되고 기억되어야 합니다. 예를 든 mode 데이터 뿐만 아니라 다른 많은 데이터가 변경되고 기억되어야 할 수도 있습니다. 이러한 데이터들의 변경사항을 반영해주고 기억해주는 창고가 바로 상태, 즉 State입니다.

2. StatefulWidget/StatelessWidget/State Widget 생성자 및 메소드

 

Flutter Material API 가이드를 통해 StatefulWidget의 생성자 및 중요 속성에 대해 정리해보도록 하겠습니다.

https://api.flutter.dev/flutter/widgets/StatefulWidget-class.html

 

StatefulWidget class - widgets library - Dart API

A widget that has mutable state. State is information that (1) can be read synchronously when the widget is built and (2) might change during the lifetime of the widget. It is the responsibility of the widget implementer to ensure that the State is promptl

api.flutter.dev

 

○ 생성자(Constructor)

<StatefulWidget 생성자>

 

 메소드(Methods)

<createState 메소드>

- 역할 : StatefulWidget 타입 매개변수를 인자로 받는 State Widget 반환

 

다음으로 StatelessWidget의 생성자 및 중요 속성에 대해 정리해보도록 하겠습니다.

https://api.flutter.dev/flutter/widgets/StatelessWidget-class.html

 

StatelessWidget class - widgets library - Dart API

A widget that does not require mutable state. A stateless widget is a widget that describes part of the user interface by building a constellation of other widgets that describe the user interface more concretely. The building process continues recursively

api.flutter.dev

○ 생성자(Constructor)

<StatelessWidget 생성자>

 메소드(Methods)

<build 메소드>

- 역할 : UI로 보여줄 Widget 반환

 

마지막으로 State Widget의 생성자 및 중요 속성에 대해 정리해보도록 하겠습니다.

https://api.flutter.dev/flutter/widgets/State-class.html

 

State class - widgets library - Dart API

The logic and internal state for a StatefulWidget. State is information that (1) can be read synchronously when the widget is built and (2) might change during the lifetime of the widget. It is the responsibility of the widget implementer to ensure that th

api.flutter.dev

 

○ 생성자(Constructor)

StatefulWidget을 상속받는 Widget을 타입 매개변수로 받는 State Widget

<State 생성자>

 

* 제네릭(Generic)

방금 State<T extends StatefulWidget>과 같이, 의미불명의 Dart 문법을 보셨습니다. State는 Widget이라는 걸 알겠는데, <T extends StatefulWidget>은 무엇을 의미하는 지 알기 어렵습니다. <>(홑화살괄호)의 의미는 타입 매개변수로써, 괄호 사이에 정의된 값으로 앞의 Widget 타입을 지정한다는 의미입니다. 즉, State의 타입을 뒤에 오는 T extends StatefulWidget 타입으로 정한다는 뜻입니다. 보통 매개변수라 하면, Scaffold(backgroundColor: Colors.grey)와 같은 인자 값을 입력받는 것이 떠오릅니다. 이번 글에선 간단히 '제네릭(Generic)이란 인자 값이 아닌 타입을 입력받아 정의하는 것을 의미한다.' 정도로 이해하시면 좋을 것 같습니다.

 

 메소드(Methods)

1) initState()

<iniState 메소드>

- 역할 : Widget이 생성될 때 처음으로 호출되는 메소드이며, 단 1번만 호출

 

2) didChangeDependencies()

<didChangeDepencies 메소드>

- 역할 : initState 메소드 이후 호출되는 메소드이며, 상속받은 Widget이 변경되었을 때도 호출

 

3) build()

<build 메소드>

- 역할 : UI로 보여줄 Widget 반환

 

4) setState()

<setState 메소드>

- 역할 : State를 변경할 때 호출하는 메소드

 

5) didUpdateWidget()

<didUpdateWidget 메소드>

- 역할 : Widget 설정이 변경될 때마다 호출되는 메소드이며, 이후 build 메소드 호출

 

6) deactivate()

<deactive 메소드>

- 역할 : Widget Tree에서 State가 제거될 때 호출되는 메소드이며, 다른 Tree에서 다시 사용할 수 있도록 영구 제거 X

 

7) dispose()

<dispose 메소드>

- 역할 : Widget Tree에서 State가 제거될 때 호출되는 메소드이며, 영구 제거 O

 

* State Lifecycle(생명주기)

<State Lifecycle / 출처 : mobikul.com/lifecycle-of-a-flutter-app>

3. StatefulWidget & StatelessWidget 예제 코드

import 'package:flutter/material.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return ModePage();
  }
}

class ModePage extends StatefulWidget {
  @override
  _ModePageState createState() => _ModePageState();
}

class _ModePageState extends State<ModePage> {
  bool mode = true;

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      themeMode: mode ? ThemeMode.light : ThemeMode.dark,
      theme: ThemeData(primaryColor: Colors.blue),
      darkTheme: ThemeData.dark(),
      home: Scaffold(
        appBar: AppBar(
          title: const Text('Mode Changer'),
        ),
        body: Center(
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: <Widget>[
              Text(
                mode ? 'Light Mode' : 'Dark Mode',
                style: const TextStyle(
                  fontSize: 30.0,
                ),
              ),
            ],
          ),
        ),
        floatingActionButton: FloatingActionButton(
          onPressed: () {
            setState(() {
              mode = !mode;
            });
          },
          child: const Icon(
            Icons.change_circle,
          ),
        ),
      ),
    );
  }
}

예제 코드의 의미는 다음과 같습니다.

  • main 함수를 생성하고 MyApp 함수 실행
    • StatelessWidget을 상속받아 MyApp Widget을 생성하고, build 메소드를 통해 ModePage() 함수 반환
      • StatefulWidget을 상속받아 ModePage Widget을 생성하고, createState 메소드를 통해 _ModePageState Widget 반환
        • ModePage Widget 타입의 State Widget을 상속받은 _ModePageState Widget을 생성
          • boolean 타입의 mode 변수를 선언하고, true 값 할당
          • build 메소드를 통해 MaterialApp 반환
            • mode 변수의 값이 true이면 light 테마, 아니면 dark 테마 설정
            • 기본 테마의 색상은 파란색으로 설정
            • dark 테마의 색상은 dark 테마로 설정
            • Scaffold Widget으로 메인 화면을 구현
              • AppBar Widget으로 상단 메뉴 구현
                • Text Widget으로 'Mode Changer'란 제목 표시
              • 가로 기준, 가운데 정렬한 Column Widget으로 본문 구성
                • 세로 기준, 가운데 정렬
                • Text Widget 생성
                  • mode 변수의 값이 true이면 'Light Mode', 아니면 'Dark Mode' 문자열 표시
                  • 글자의 크기는 30.0
              • FloatingActionButton으로 버튼 구성
                • 버튼을 누르면, 현재 mode의 값을 반대 boolean 값으로 설정(true -> false 또는 false -> true)
                • 버튼을 change_circle 모양으로 설정

4. StatefulWidget & StatelessWidget 실행 결과

<Light Mode 실행 결과>
<Dark Mode 실행 결과>

'App Programming > Flutter' 카테고리의 다른 글

[Flutter] Widget - ListTile  (0) 2022.05.11
[Flutter] Widget - Card  (0) 2022.05.11
[Flutter] Widget - ListView  (0) 2022.05.05
[Flutter] Widget - Expanded  (0) 2022.04.24
[Flutter] Widget - Row  (0) 2022.04.18

댓글