[Flutter] Stateless, Stateful Widget

2022. 12. 30. 14:44·🐦 플러터

State가 뭔데

  • State는 데이터이다?
  • State는 UI가 변경되도록 영향을 미치는 데이터라고 생각하면 좋을 거 같다.
  • 데이터에 대해서 좁은 범위로 생각해선 안된다. 데이터를 넓은 범위의 데이터로 생각해야 한다.
  • App 수준의 좁은 범위의 데이터는 로그인 인증 데이터나 서버에서 관리하는 데이터 등이 있지만, Widget 수준의 넓은 범위의 데이터에는 checkbox에 체크가 되었는지, textbox에 text가 입력되었는지 등 Widget 수준의 데이터까지도 state라고 생각하는 것이 좋다.

Widget tree, Element tree, 그리고 Render tree 라는 건 뭔데

  • Widget tree
    • 코드 상에서 얼마든지 개발자가 관리할 수 있다.
    • 우리가 작성한 코드에 근거해서 플러터가 위젯들을 생성한다.
    • 일종의 설계도로써, 직접적으로 스크린에 보여지지 않고, 순서를 위젯 순서대로 스크린에 보여달라고 플러터에 요청하는 역할이다.
  • Element tree & Render tree 공통점
    • 플러터가 내부적으로 관리하는 부분.
    • Widget tree에 근거해서 생성된다.
  • Element tree
    • 이 세 트리 중에서 실제로 제일 중요한 부분이다.
    • Widget tree와 Render tree를 연결시켜주는 중간 다리 역할이라고 할 수 있다.
    • 위젯 트리에서 만든 위젯들 하나하나가 Element tree와 일대일 맞대응 하고 있다.
  • Render tree
    • Screen에 표시를 해주는 일종의 high-level system이다.
    • Render tree 역시 Element tree와 일대일 맞대응하고 있다.
    • 최종적으로 우리가 애뮬레이터에서 보고있는 모든 작업물들은 Render tree에서 보여지는 녀석들이다.

코딩 셰프 - tree 구조를 그림으로 표시한 장면


Element tree는 Widget tree에서 자신과 대응하는 위젯을 그대로 복사하기 때문에 복사한 위젯의 모든 속성과 타입 등을 모두 가지고 있다. 따라서 위치, 타입, 그리고 속성 등이 일치하는 경우에는 Widget tree에서 대응하는 위젯이 변경되었다고 해서 똑같이 리빌드 되는 것이 아니라 그대로 링크만 업데이트된다. 그래서 그 정보를 Render Object에 넘겨주게 되고 바뀐 부분만 다시 보여주게 되는 것이다.

코딩 셰프 - tree에서 데이터가 이동하는 과정


Stateless Widget

  • State가 변하지 않는 위젯
  • 한 번 지정된 layout이나 Text, Color 등의 데이터는 위젯 자체가 리빌드되지 않는 한 변하지 않는다.
    • Stateless Widget은 rebuild만을 통해서 새로운 State 적용 가능하다.
    • 60 fps 속도로 rebuild
  • Stateless Widget은 간단하게 말하자면 생산단가가 매우 저렴해서 한 번 쓰고 버리면 그만인 위젯이다.

Stateful Widget

  • Stateful Widget이 Stateless Widget과의 가장 큰 차이점이라면, Stateful Widget은 State라는 클래스와 결합되어 있다는 점이다.
  • Stateful Widget의 리빌드를 유발하는 것은 결과적으로 widget과 결합되어 있는 State 클래스이며, 이를 통해 스크린 UI를 다시 렌더링 하게 된다.
  • Stateful Widget이 리빌드 되는 경우?
    • child의 생성자를 통해서 데이터가 전달되었을 때
    • internal state가 변경되었을 때

class MyHomePage extends StatefulWidget {
  const MyHomePage({super.key, required this.title});
  final String title;

  // StatefulWidget 이 생성될 떄마다 호출되는 메소드
  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  int _counter = 0;

  void _incrementCounter() {
    setState(() {
      _counter++;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            const Text(
              'You have pushed the button this many times:',
            ),
            Text(
              '$_counter',
              style: Theme.of(context).textTheme.headline4,
            ),
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: _incrementCounter,
        tooltip: 'Increment',
        child: const Icon(Icons.add),
      ), // This trailing comma makes auto-formatting nicer for build methods.
    );
  }
}

StatefulWidget 을 두 덩이로 나눈 이유?

StatefulWidget 은 Widget을 상속하는데 Widget은 immutable 하다는 특징이 있다.
즉, StatelessWidget 처럼 변동이 있으면 안된다는 이야기이다.
따라서 Widget의 특징도 따르고, StatefulWidget의 가변성도 따르기 위해서 두 덩이로 나눈 것이다.


그렇다면 어떻게 두 덩이를 하나로 결합시킬 수 있는가

State 클래스를 살펴보면 Generic으로 타입을 지정받는 걸 볼 수 있다.
따라서, <MyHomePage>로 타입을 지정해주면 결과적으로 _MyHomePageState 가 MyHomePage 와 연결이 되는 것이다.
그렇다면, 왜 State는 Generic으로 타입을 받는 것일까? 그 이유는 Generic의 장점인 코드 재사용성과 안정성 때문이다.
연결이 필요한 Stateful Widget을 지정만 해주면 문제가 간단히 해결된다.


참고

코딩셰프 Stateful 위젯 강좌1, 2 - https://youtu.be/OvWrOKMqSG0

 

저작자표시 비영리 동일조건 (새창열림)

'🐦 플러터' 카테고리의 다른 글

[iOS] 플러터 IOS 시뮬레이터에서 Google 간편 로그인 안될 때  (0) 2023.01.05
[ERROR:flutter/runtime/dart_vm_initializer.cc(41)] Unhandled Exception: 'package:firebase_auth_platform_interface/src/providers/google_auth.dart': Failed assertion: line 43 pos 12: 'accessToken != null || idToken != null' ...  (0) 2023.01.04
[Flutter] Navigator 이해하기  (0) 2022.12.24
[Flutter] Container Widget 이해하기  (0) 2022.12.24
[Flutter] BuildContext + Snack Bar 이해하기  (0) 2022.12.24
'🐦 플러터' 카테고리의 다른 글
  • [iOS] 플러터 IOS 시뮬레이터에서 Google 간편 로그인 안될 때
  • [ERROR:flutter/runtime/dart_vm_initializer.cc(41)] Unhandled Exception: 'package:firebase_auth_platform_interface/src/providers/google_auth.dart': Failed assertion: line 43 pos 12: 'accessToken != null || idToken != null' ...
  • [Flutter] Navigator 이해하기
  • [Flutter] Container Widget 이해하기
기멘기
기멘기
Handong Global University | Apple Developer Academy @ POSTECH
  • 기멘기
    현기의 비공식문서 🍎
    기멘기
  • 전체
    오늘
    어제

  • 링크

    • Github
    • Instagram

    • 전체 글 (79)
      • 🍎 iOS (6)
        • 애플 디벨로퍼 아카데미 (6)
      • 🐦 플러터 (32)
      • 🤔 컴공 지식 (10)
        • 알고리즘 (3)
        • 네트워크 (7)
      • 🔥 문해력 상승 (8)
        • 백 준 (8)
        • 프로 그래머 스 (0)
      • 💬 이모저모 (12)
        • CRA 방학 프로젝트 (4)
        • 캡스톤 산학 프로젝트 (5)
        • PARD IT 협업 동아리 (2)
      • 💡 인사이트 (0)
        • 전공 관련 (0)
        • 기타 (0)
      • ✏️ 하루 회고 (TIL) (4)
      • 🔍 ETC (7)
        • HTML-CSS-JS (4)

  • 인기 글


  • 최근 댓글


  • 최근 글


  • 블로그 메뉴

    • 티스토리 홈
    • 블로그 관리
    • 글 작성하기

  • hELLO· Designed By정상우.v4.10.3
기멘기
[Flutter] Stateless, Stateful Widget
상단으로

티스토리툴바