본문 바로가기
App/Flutter

[Flutter] Stateless 위젯과 Stateful 위젯

by r4bb1t 2022. 1. 15.
반응형

플러터에서 위젯은 크게 두 가지 종류가 있습니다. Stateless 위젯과 Stateful 위젯입니다.

Stateless 위젯

불변(immutable)한 위젯입니다. 최초에 만들어져 화면에 그려지고 나면, 위젯을 삭제하고 새로운 위젯을 만들지 않는 이상 수정되지 않습니다. 그래서 생명주기(life cycle)를 거의 고려하지 않아도 괜찮습니다.

material.dart 파일을 import하고 Stateless 위젯을 만들어 봅시다.

import 'package:flutter/material.dart';

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(),
    );
  }
}

 

stless를 입력하고 엔터를 눌러 자동완성하거나, 안드로이드 스튜디오에서 새 플러터 프로젝트를 시작하면 나오는 코드를 봐도 됩니다. MyHomePage도 Stateless로 만들어봐요.

class MyHomePage extends StatelessWidget { 
  @override
  Widget build(BuildContext context) {
    return Container(
      color: Colors.pink,
      child: Padding(
        padding: EdgeInsets.all(30),
        child: Container(
          color: Colors.white,
        ),
      ),
    );
  }
}

와!

이제 버튼을 넣어봅시다.

class MyHomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Container(
        color: Colors.pink,
        child: Padding(
          padding: EdgeInsets.all(30),
          child: Container(
            color: Colors.white,
          ),
        ),
      ),
      floatingActionButton: FloatingActionButton(onPressed: () {}),
    );
  }
}

 

FloatingActionButton을 넣기 위해 전체를 Scaffold로 감싸줍니다. Scaffold는 앱의 기본 토대같은 위젯으로. 앱의 상단(appBar), 중간(body), 하단(bottomNavigationBar), 그리고 떠 있는 버튼(floatingActionButton)의 구조를 만들 수 있게 해줍니다.

FloatingActionButton이 생겼습니다. 이제 눌렀을 때 어떤 반응을 하게 만들어봅시다.

class MyHomePage extends StatelessWidget {
  int a = 0;
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Container(
          color: Colors.pink,
          child: Padding(
              padding: EdgeInsets.all(30),
              child: Container(
                  color: Colors.white,
                  width: double.infinity,
                  height: double.infinity,
                  child: Center(child: Text("$a"))))),
      floatingActionButton: FloatingActionButton(onPressed: () {
        a++;
      }),
    );
  }
}

 

왠지 이렇게 하면 버튼을 눌렀을 때 a의 값이 증가하며 화면에도 증가한 a의 값이 표시될 것 같습니다. 하지만 아무리 버튼을 눌러도 계속 0만 화면에 떠있을 것입니다. 왜일까요? MyHomePage가 Stateless 위젯이기 때문입니다. Stateless 위젯은 한 번 화면에 그려지고 나면 변하지 않습니다. a++ 밑에 print(a)를 넣어 콘솔을 찍어보면,

이렇게 a의 값은 정상적으로 증가하고 있습니다. 화면에 반영되지 않을 뿐입니다. 이럴 경우, 변경된 상태를 바로바로 화면에 반영해주기 위해서 Stateful 위젯을 쓰면 됩니다.

stful을 입력하고 엔터를 누른 후 다시 MyHomePage를 작성해봅니다.

class _MyHomePageState extends State<MyHomePage> {
  int a = 0;
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Container(
          color: Colors.pink,
          child: Padding(
              padding: EdgeInsets.all(30),
              child: Container(
                  color: Colors.white,
                  width: double.infinity,
                  height: double.infinity,
                  child: Center(child: Text("$a"))))),
      floatingActionButton: FloatingActionButton(onPressed: () {
        a++;
        print(a);
      }),
    );
  }
}

 

하지만 역시 버튼을 눌러도 화면에는 반영되지 않습니다. 상태가 변경된 것을 화면에 반영해주고 싶다면, setState를 사용해야 합니다.

class _MyHomePageState extends State<MyHomePage> {
  int a = 0;
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Container(
          color: Colors.pink,
          child: Padding(
              padding: EdgeInsets.all(30),
              child: Container(
                  color: Colors.white,
                  width: double.infinity,
                  height: double.infinity,
                  child: Center(child: Text("$a"))))),
      floatingActionButton: FloatingActionButton(onPressed: () {
        setState(() {
          a++;
        });
        print(a);
      }),
    );
  }
}

 

a++를 setState(( ){ }) 안에 넣어주었습니다.

이제 잘 반영됩니다.

Stateless 위젯은 한번 그려지면 변하지 않지만 그만큼 그려지는 속도가 빠르고, Stateful 위젯은 변경되는 상태를 바로 반영할 수 있으니 두 가지 종류의 위젯을 잘 구분해서 사용해야 합니다.

반응형

댓글