최근 Flutter 공부를 시작했다. 처음으로 마주한게 Stateful과 Stateless 위젯이었다. 그 차이점에 대해 정리해보고자 한다.
1. 공식 문서 설명
이름부터 Stateful은 변경이 되고, Stateless는 변경이 되지 않을 것 같다는 느낌을 받았다. 공식문서에서 설명하는 걸 옮겨보자면 아래와 같다.
stateless 위젯은 변하지 않는 위젯이다.
stateful 위젯은 유저와의 상호작용 또는 데이터 수신과 같은 이벤트에 대한 응답으로 위젯의 모습을 바꿀 수 있는 위젯이다.
위젯의 상태는 State object에 저장되며, state가 변경되면 State object는 SetState()를 호출하여 프레임워크로 하여금 위젯을 다시 그리게 한다.
2. 위젯의 생명주기
두 위젯의 생명주기 또한 다르다.
그림에서 볼 수 있듯이 Stateless 위젯은 생성자 호출 후, build 메서드를 호출하여 위젯을 그리는데, BuildContext를 인자로 받아서 호출한다.
Stateful 위젯도 마찬가지로 생성자 호출 후, build 메서드를 호출하지만 그 사이 과정이 더 있는 것을 볼 수 있다.
1. createState() : State 인스턴스를 생성하는 메서드다. stless 자동으로 생성되는 코드 스니펫에 있는 그 메서드이다.
2. mounted == true : State 인스턴스가 생성되면 해당 instance의 mounted 속성은 true가 되는데, 해당 속성은 해당 인스턴스가 위젯 트리에 있는지에 대한 정보이다. (위젯 트리에서 제거되면 mounted는 false가 되고, 이 상태에서 setState를 호출하면 에러가 발생한다.)
2. initState() : 말 그대로 State를 초기화하는 메서드이다. 인스턴스 생성 시에만 호출되며, 여기서 초기화 관련 코드나 위젯의 데이터에 변경을 야기할 수 있는 것들을 subscribe 하기 적절하다고 한다.
3. didChangeDependencies() : initState 직후 호출되며, build 메서드는 이 메서드 이후 호출된다. (+ 위젯이 data에 의한 변화에 의존하는 object인 경우에도 호출된다)
4. build() : 최초에도 호출되며 Widget을 반환하는 필수적인 메서드이다. setState(), didUpdateWidget() 메서드가 호출 될 때마다 호출된다.
5. didUpdateWidget() : 부모 위젯이 변경되어 이 위젯을 다시 빌드해야 하는 경우 호출되며, 인수로 oldWidget을 제공하기 때문에 이전 위젯과 현재 위젯을 비교할 수 있다.
5. setState() : 데이터가 변경되었음을 알리는 메서드, 이 메서드 호출 후 다시 build 메서드가 호출된다.
6. deActivate() : 위젯 트리에서 위젯이 제거될 때(제거되고 프레임 작업 완료되기 전에 다시 삽입될 수 있음), 위젯 트리 내에서 다른 지점으로 이동할 때 호출된다.
7. dispose() : State 인스턴스가 영구적으로 제거될 때 호출된다.
8. mouted == false : dispose 메서드 호출 후 mounted는 false가 되며 State 인스턴스가 없기 때문에 setState 메서드 호출 시 에러가 발생한다.
BuildContext란?
1. BuildContext는 위젯 트리에서 현재 widget의 위치에 대한 정보를 가지고 있는 것
2. BuildContext는 Stateless 위젯이나, State의 build 메서드에 의해 리턴된 위젯의 부모가 된다.
두번째 설명이 이해가 되지 않아 정리해보자면, App 위젯의 BuildContext를 가지고 build 메서드가 호출되기 때문에 CupertinoApp 위젯 내에서 context를 그냥 참조하려고 하면 자신의 BuildContext가 아니라 부모, 즉 App 위젯의 BuildContext를 참조하게 된다는 것이다.
3. 위젯 코드 빠르게 작성하기
우선 둘 다 간편하게 생성할 수 있었는데, Stateful의 경우 stful을 Stateless의 경우 stless를 입력하면 사진처럼 위젯 이름만 작성하면 되게끔 자동 완성이 된다. 서로간의 변환도 자동으로 해주기 때문에 수정할 때도 편리하게 할 수 있었다.
참고
https://docs.flutter.dev/development/ui/interactive
https://flutterbyexample.com/lesson/stateful-widget-lifecycle