stateful, stateless widget

이동완·2024년 3월 3일
  • StateFul : 별도의 State객체를 통해 위젯에 색깔, 형태 등을 바꿀 수 있는 위젯
  • Stateless : 정적으로, 화면에 위젯을 다시 그리려면, 수동으로 화면을 리로드 해야되는 위젯
import 'package:flutter/material.dart';

void main() {
  runApp(
    MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text('Stateful , Stateless'),
        ),
        body: Body(),
      ),
    ),
  );
}

class Body extends StatelessWidget{
  const Body({super.key});

  @override
  Widget build(BuildContext context){
    return Column(
      children: [
        ExampleStateless(),
        ExampleStateful(),
        ],
    );
  }
}

class ExampleStateless extends StatelessWidget{
  const ExampleStateless({super.key});

  @override
  Widget build(BuildContext context) {
    return Container(
      color: Colors.red,
    );
  }
}

class ExampleStateful extends StatefulWidget {
  const ExampleStateful({super.key});

  @override
  State<ExampleStateful> createState() => _ExampleStatefulState();
}

class _ExampleStatefulState extends State<ExampleStateful> {
  @override
  Widget build(BuildContext context) {
    return Container(
      color: Colors.blue,
    );
  }
}

위의 코드는 가장 기본적인 Stateless 위젯과 Stateful 위젯을 만드는 코드이다.

Stateful의 코드는 Stateless와 다르게 stful을 치고 enter를 누르면 자체적인 클래스가 생성이 된다.
하지만 위의 코드대로 했을 때 Column으로 container를 두 개를 나누어 놓고 위의 container에는 red, 아래의 container에는 blue의 색을 설정했다면 그 설정대로 결과가 나와야 겠지만
결과는 이렇다

왜냐하면 container에 사이즈를 저장하지 않았기 때문이다.
이를 해결하려면 저번 시간에 했던것 처럼 container를 Expanded로 감싸야 한다.

class ExampleStateless extends StatelessWidget{
  const ExampleStateless({super.key});

  @override
  Widget build(BuildContext context) {
    return Expanded(
      child: Container(
        color: Colors.red,
      ),
    );
  }
}

class ExampleStateful extends StatefulWidget {
  const ExampleStateful({super.key});

  @override
  State<ExampleStateful> createState() => _ExampleStatefulState();
}

class _ExampleStatefulState extends State<ExampleStateful> {
  @override
  Widget build(BuildContext context) {
    return Expanded(
      child: Container(
        color: Colors.blue,
      ),
    );
  }
}

이건 container를 Expanded로 감쌌을 때의 코드이다.

이렇게 container를 Expanded로 감싸 container에 사이즈를 저장한다면

위와 같이 우리가 목표로 했던 설정이 나오게 된다.

먼저 Stateful 위젯이다.

class ExampleStateful extends StatefulWidget {
  const ExampleStateful({super.key});

  @override
  State<ExampleStateful> createState() => _ExampleStatefulState();
}

class _ExampleStatefulState extends State<ExampleStateful> {
  int index = 0;


  @override
  Widget build(BuildContext context) {
    return Expanded(
      flex: 1,
      child: GestureDetector(
        onTap: () {
          
          if(index==5) {
            index = 0;
            return;
          }
          index++;

        },
        child: Container(
          color: Colors.blue,
          child: Center(
            child: Text('$index'),),
          ),
      ),
    );
  }
}

해당 코드는 위의 코드에서 GestureDetector를 통해 터치를 하면 index가 증가하는 코드를 추가하여 stateful을 이용한 것이다.

보면 나는 5번을 클릭하여 index의 숫자 5가 올라가 있는데 사실 이건 실시간으로 올라간 것이 아니라 클릭한 후 재시작을 하여 이미 클릭된 기록이 추가되어 화면에 보이는 것이다.
이렇게 실시간으로 index의 변화가 보이지 않은 이유는 state가 변했다는 것을 위젯에게 알려줘야될 필요가 있기 때문이다.
그걸 위한 코드가 setState이다.

setstate

  • setstate가 선언되면 상위 위젯으로 알려져 위젯이 다시 빌드 된다.
@override
  Widget build(BuildContext context) {
    return Expanded(
      flex: 1,
      child: GestureDetector(
        onTap: () {
          setState(() {
            if(index==5) {
              index = 0;
              return;
            }
            index++;


          });

        },
        child: Container(
          color: Colors.blue,
          child: Center(
            child: Text('$index'),),
          ),
      ),
    );
  }
}

setState를 추가한 부분만 가져온 코드이다.
위와같이 setstate를 추가한 후 실행시켜주면 클릭할 때마다 index가 오르는게 위젯에서 보이고 최대 5까지 증가하고 5이상에선 0으로 초기화 되는 위젯을 볼 수 있다.
또한 color에 대한 코드를

color: Colors.blue.withOpacity(index/5)

이런식으로 변경한다면 클릭할 때마다 인덱스의 숫자와 그에 맞춰 숫자가 올라갈 때마다 색이 짙어지게 할 수도 있다.

또한 재시작을 했을 때 index의 값이 변하면 안될 때는

class _ExampleStatefulState extends State<ExampleStateful> {
  late int index;


  @override
  void initState() {
    super.initState();
    index = 5;
  }

위와 같이 alt+o를 눌러 initstate를 선택하고 위의 코드처럼 만들어주면 된다.
그러면 재시작하였을 때 initState안에서 설정한 index값으로 실행하게 되고 super.iniState()를 통해 상위 State에도 initState가 같이 적용된다.

Stateful 위젯과 Stateless 위젯의 차이점

  • 위젯 안에서 state가 변경됨에 따라 화면이 바뀌는 위젯 : stateful 위젯
  • 그렇지 않고 앱 바와 같은 형태로 고정적인 한 색깔(화면)만 보이는 위젯 : stateless 위젯
profile
이동완

0개의 댓글