Flutter/UI Widget

[Flutter] StatelessWidget vs StatefulWidget

개발자킹콩 2023. 4. 6. 14:49

목차

  1. StatelessWidget vs StatefulWidget
  2. StatelessWidget
    1. StatelessWidget Life Cycle
    2. StatelessWidget 특성
  3. StatefulWidget
    1. StatefulWidget 특성
    2. StatefulWidget Life Cycle
    3. StatefulWidget Life Cycle 이해를 돕기위한 3가지 예시 
      1. 상태변경이 없는 생명주기
      2. StatefulWidget 생성자의 매개변수가 변경됐을 때 생명주기(Stateful을 이해하기 좋음)
      3. State 자체적으로 build() 를 재실행할 때 생명주기 

 

 

 


 

 

 

1. StatelessWidget vs StatefulWidget

StatelessWidget: 위젯 내부에서 값이 변경되어도, 위젯 자체적으로 다시 렌더링할 수 없는, 상태를 관리할 수 없는 위젯

StatefulWidget: 위젯 내부에서 값이 변경되었을때, 위젯 자체에서 다시 렌더링을 시킬 수 있는, 상태를 관리할 수 있는 위젯

 

플러터에서 UI를 표현할 때 대표적인 위젯은 StatelessWidget과 StatefulWidget이 있습니다. 이 두 위젯의 Life Cycle를 통해 상태 관리에 대한 이해를 배워보겠습니다. 여기서 Life Cycle이란 생명주기를 뜻하며, 객체의 생성과 동작하는 것, 소멸할 때까지의 일련의 과정, 주기를 의미합니다. 아래는 StatelessWidget과 StatefulWidget의 Life Cycle입니다.

 

 

 

 

지금은 "아~ 이런게 있구나~" 정도만 이해하고 넘어갑시다!

 

 

 

 


 

 

 

 

2. StatelessWidget(상태를 관리할 수 없는 위젯)

위젯 내부에서 값이 변경되어도, 위젯 자체적으로 다시 렌더링 불가능

 

 

1. StatelessWidget Life Cycle

StatelessWidget의 Life Cycle은 다음과 같이 간단한 구조입니다.

1) StatelessWidget이 빌드되면 생성자 실행

2) 필수로 override 해야하는 build() 함수 실행

3) build() 함수에 반환한 위젯이 화면에 렌더링

 

 

 


 

 

2. StatelessWidget의 특성

플러터에서 모든 위젯은 Widget 클래스를 상속합니다. Widget 클래스는 immutable 불변 특성을 갖고 있습니다. 한 번 생성하고 나면 속성을 변경할 수 없습니다. 즉, 플러터의 모든 위젯은 한 번 생성하면 속성을 변경할 수 없는 immutable 특성을 갖습니다.

 

 

하지만 위젯의 속성을 변경해야 할 때는 분명 있습니다. 생성자에 새로운 매개변수가 입력되는 경우입니다. build() 함수에서 매개변수 값을 사용하고 있다면 변경된 매개변수를 기반으로 build() 함수를 재실행 해줘야 합니다. 하지만 StatelessWidget은 불변이기 때문에 한번 생성된 인스턴스의 build() 함수는 재실행 되지 않습니다. 대신 인스턴스를 아예 새로 생성한 후 기존 인스턴스를 대체해서 변경 사항을 화면에 반영합니다.

 

 

예를 들어 위의 MyApp의 속성인 title이 바껴야 하는 경우입니다. 그럼 MaterialApp의 title이 변경되는 것이고 build() 함수가 재실행 되어야 함을 의미합니다. 하지만, 재실행 되지 않고(할 수도 없고) 새로운 인스턴스를 생성해서 build() 함수를 실행하게 됩니다.

 

 

 

 


 

 

 

3. StatefulWidget(상태를 관리할 수 있는 위젯)

위젯 내부에서 값이 변경되었을때, 위젯 자체에서 다시 렌더링을 가능

 

 

1. StatefulWidget의 특성

 

 

StatefulWidget 또한 Widget을 상속하여 immutable 한 특징을 그대로 갖습니다. 하지만 StatefulWidget은 StatelessWidget과 다르게 위젯 내부에서 자체적으로 build() 함수를 재실행 가능합니다. 그게 어떻게 가능한 걸까요?? 그 답은 StatefulWidget은 위젯클래스와 State 클래스 2개로 구성되어 있기 때문입니다.

 

 

StatefulWidget은 StatelessWidget과 마찬가지로 외부에서 위젯 생성자의 매개변수를 변경해주면 위젯이 새롭게 생성되고 build() 함수가 실행되기까지 과정은 같습니다. 이 말은 혼란의 야기할 수 있기에 추가 설명을 하면 다음과 같습니다. StatefulWidget 또한 Widget을 상속받고 immutable한 속성을 그대로 갖습니다. 즉, StatefulWidget 생성 시 필요한 매개변수의 변화는 인스턴스 재생성이 필요함을 나타내며 Stateless와 똑같이 진행됩니다. 

 

차이점은 StatefulWidget의 생성 시 필요한 매개변수가 아니라 상태 관리가 필요한 변수가 변화 했을 때입니다. 즉, StatefulWidget의 변수가 아닌 State의 변수가 변경 되면 이 차이점을 명확히 알 수 있습니다. 이 때는 StatelessWidget과 다르게 인스턴스를 재생성하지 않고 build() 함수를 실행가능합니다. 이를 가능캐하고 제어하는 것은 State 클래스입니다. State 클래스는 Widget이 아니기에 immutable한 특징이 없고 build()를 제어하기 위해 만들어 졌습니다. 그렇기에 상태관리가 필요한 변수들은 당연히 State에 몰아 넣어야 합니다. 

 

 

 

 


 

 

 

2. StatefulWidget Life Cycle

상세한 생명주기는 아래와 같이 10단계를 가집니다.

가장 기본이 되는 것은 initState()와 build(), setState()이다.

 

 

1. createState() : 상태 생성

  - StatefulWidget이 처음 생성될때 반드시 호출하는 함수

  - StatefulWidget은 필수적으로 오버라이딩 해야 함

 

2. mounted == true : setState() 호출 가능 상태

  - State가 생성되면 mounted property가 true로 설정 됨

  - 위젯을 제어할 수 있는 buildContext 클래스에 접근 가능해지며 setState()를 호출할 수 있게 됨

  - setState() 호출전에 mounted property를 체크하면 더 안전한 코드를 작성할 수 있음

 

3. initState() : State 초기화

  - State 생성 시 딱 한번만 호출되며 초기화하는 작업

  - 위젯에서 필요한 데이터를 준비하고 작성하기 좋은 구간

 

4. didChangeDependencies() : 의존성 변경 시 호출

  - initState() 이후에 호출

  - initState() 와 다르게 BuildContext가 제공되어 State가 의존하는 값이 변경되면 재실행 됨

  - 상속받은 위젯을 사용할때 Super(Parent)가 변경되면 호출 함

  - ex: (해당 위젯이 업데이트 되거나, 상속한 위젯이 업데이트 되는 경우 등) 

  - ex: 네트워크(API) 호출이 필요한 위젯과 같이 데이터에 의존하는 위젯이라면 화면에 표시하기 전에 꼭 호출 해야 함

 

5. build() : 반환 위젯 빌드

  - 위젯을 만들어주는 메소드이다. 반환되는 위젯을 렌더링 함

  - State 클래스는 build()를 필수적으로 오버라이딩 해야 함

 

6. didUpdateWidget() : 위젯 갱신시 호출되는 메소드

  - StatefulWidget이 매개변수 변경되어 재생성 될 때 실행되는 함수

  - Parent 위젯이나 데이터가 변경되어 위젯을 갱신해야 할 때 호출 됨

  - 위젯이 생성되고 나서 갱신을 해야 할때는 initState()가 아니라 didUpdateWidget()이 호출된다. 그렇기에 갱신에 필요한 코드는 didUpdateWidget() 에 구현해야 함

 

7. setState() : 실행 중에 변경사항을 알리는 메소드  

  - 데이터가 변경 되었다는 것을 알리고 다시 build() 메소드를 실행시켜 UI를 갱신 함

  - 상태 갱신이 필요한 부분에 사용

 

8. deactivate() - 메모리 해제 전에 상태 관리를 멈추는 작업(상태 관리 멈춰!)

  - State가 소멸전에 플러터의 구성 트리로부터 제거되는 메소드

  - 따라서, 관리는 되지 않으나 메모리 해제까지 한것은 아니라 사용은 가능함

 

9. dispose() - 메모리 해제(상태 관리 끝)

  - State 위젯을 완전히 소멸함

  - 위젯을 없앨 때 해줘야 하는 작업이 있다면 여기에 작성

  - deactivate() 된 위젯을 다른 트리에서 재사용하는 경우 dispose()가 호출되지 않을 수 있음

  - 내부 Listener들을 삭제한 이후 super.dispose() 를 실행해야 함

 

10. mounted == false :  setState() 호출 불가능 상태

  - 더 이상 stateful 위젯이 존재하지 않으므로,  setState()메소드 사용이 불가함을 설정함.

 

 

 

 

 


 

 

 

 

3. StatefulWidget Life Cycle 이해를 돕기위한 3가지 예시 

StatefulWidget 의 Lift cycle 중 우선 이해할 생명주기 3가지는 다음과 같습니다.

 

 

 

 


 

 

 

1) 상태 변경이 없는 생명주기

제일 기본적인 상태이며 StatefulWidget이 생성되고 소멸되는 전반적인 과정이다.

 

 

1) StatefulWidget 생성자 실행됩니다.

2) State를 생성하는 (필수로 오버라이드 되어야 하는) createState() 함수 실행됩니다.

3) State가 생성되는 순간에 단 한번 호출되는 initState() 실행됩니다.

4) didChangeDependencies() 실행 됩니다. 처음 생성될 때는 반드시 호출됩니다.

5) State의 상태가 dirty로 설정됩니다. dirty 상태는 build()가 재실행 되어야 하는 상태입니다.

6) build() 함수가 실행되고 UI가 반영됩니다.

7) build() 실행이 완료되면 상태가 clean 상태로 변경됩니다. 변화가 없으면 이 상태를 유지합니다. (대기 상태)

8) 위젯이 위젯트리에서 사라지면 deactivate() 가 실행됩니다. deactivate()는 State가 일시적으로 또는 영구적으로 삭제될 때 실행됩니다. (삭제 대기)

9) dispose()가 실행됩니다. 위젯이 영구적으로 삭제될 때 실행됩니다.

 

 

 


 

 

 

2) (생성이 된 이후에) StatefulWidget 생성자의 매개변수가 변경됐을때 생명주기

StatelessWidget과 동일하게 StatefulWidget도 생성자의 매개변수가 변경되면 인스턴스를 재생성합니다. 하지만, State를 재생성 하지는 않는다. State는 소멸되기 전에 딱 한번만 생성되고 유지됩니다.

 

자세하게 설명하면 State에서 관리하는 변수가 아닌 StatefulWidget을 생성할 때 필요했던 매개변수의 값이 바뀔 때의 상황입니다. 이렇게 되면 StatelessWidget과 마찬가지로 StatefulWidget 또한 인스턴스를 재생성 합니다. 그럼 소멸되는 기존 위젯(oldStatefulWidget)은 새롭게 생성되는 위젯(newStatefulWidget)에게 State를 전달하게 됩니다. 그럼 State에게 앞으로 모실 Widget이 무엇인지 인지시켜줘야 겠죠. 그때 호출되는 것이 didUpdateWidget() 입니다. StatefulWidget

 

 

실제 didUpdateWidget() 에서는 소멸되는 기존 위젯에 대해 마지막 남길 유언 정도 들어주기 위해 만들어졌습니다. StatefulWidget의 매개변수 변경으로 새롭게 인스턴스를 생성하게 되면 build() 를 재실행하게 됩니다 .이때 State에서 기존 StatefulWidget이 갖고 있는 값 이나 그 값에 따른 controller를 갖고 있어서 재실행의 오류가 발생한는 경우가 존재합니다. 새로운 StatefulWidget 이 State를 온전히 제어가능 하도록 구현할 수 있도록 하는 함수입니다. (기억하세요! StatefulWidget 매개변수 값이 변경되면 StatefulWidget의 인스턴스를 새롭게 재생성하고 didUpdateWidget이 알아서 호출됩니다!)

 

 

 

1) StatefulWidget의 매개변수가 변경되면, StatefulWidget 생성자가 실행된다.

2) 이때, State는 clean상태(대기상태)에 있었으며, didUpdateWidget() 함수를 실행된다.

3) State가 dirty상태(build()함수 실행대기 상태)로 변경된다.

4) build() 함수가 실행된다.

5) State 의 상태가 clean 상태로 변경된다.

 

 

 


 

 

 

3) State 자체적으로 build() 를 재실행할 때 생명주기

didUpdateWidget()은 실행되는 타이밍이 존재하고 그때 개발자의 코드를 추가해 제어하는 방법입니다.

setState()는 실행되는 타이밍도, 나의 코드도 모두 개발자가 제어합니다. 

 

 

1) setState() 실행한다.

2) dirty 상태가 된다.

3) build() 함수가 실행된다.

4) clean 상태가 된다.

 

 

 

 

 


 

 

 

 

Reference

 

https://www.flutterclutter.dev/flutter/basics/statelesswidget-vs-statefulwidget/2020/1195/

 

StatelessWidget vs. StatefulWidget

Answering one of the most frequently asked question of Flutter beginners: what is the difference between StatelessWidget and StatefulWidget?

www.flutterclutter.dev

 

https://bangu4.tistory.com/312

 

[Flutter] 앱 생명주기와 Stateful , Stateless 위젯

앱을 구성하는 하나의 클래스를 만들때, 우리는 그 위젯의 속성의 따라 Stateful , Stateless 두가지 종류의 클래스를 만들 수 있다. Stateless 는 변경 불가능 하며, 모든 값이 final 상수지만, 반면, Statefu

bangu4.tistory.com

 

https://link.coupang.com/a/T0jF1

 

Must Have 코드팩토리의 플러터 프로그래밍:Dart & Flutter 입문부터 실전에 유용한 10가지 앱 개발과

COUPANG

www.coupang.com

"이 포스팅은 쿠팡 파트너스 활동의 일환으로, 이에 따른 일정액의 수수료를 제공받습니다."