이번 포스트에서는 Flutter의 상태 관리가 필요한 이유와 효율적으로 관리하기 위해 상태 관리 라이브러리를 사용해야 하는 이유에 대해 알아보겠습니다.
Flutter의 상태 관리
Flutter를 이용해서 앱을 만들 때 상태 관리(State Management)
가 왜 중요한가에 대해 먼저 생각해볼 필요가 있습니다.
Win32, Android, iOS 등 기존에 사용하던 프레임워크들에서 명령형 UI 프로그래밍 방식을 사용했었습니다. (but, 지금은 선언형으로 넘어가는 추세) 이러한 명령형 UI 프로그래밍 방식은 UI 엔티티를 수동으로 작성하여 UI를 변경할 수 있는 메소드 혹은 setter 메소드를 호출해서 수동으로 변경하였습니다.(예를 들면, textView.setText)
하지만, Flutter의 UI 구성 방식은 선언형(declarative) 프로그래밍 방식
이므로 앱의 상태(state)를 반영하여 UI를 build합니다. 즉, 명령형 UI와 다르게 선언형 UI는 UI를 강제적으로 변경할 필요 없이 앱의 상태만 변경해주면 됩니다. 그러면 UI를 변경하기 위해 자체적으로 rebuild(Flutter에서는 일반적으로 setState 메소드)를 트리거하여 새로운 위젯 하위 트리를 구성합니다. 그러므로, 이러한 상태를 포함하는 위젯 트리 기반의 선언형 UI 프로그래밍 방식에서는 상태 관리가 매우 중요하다고 할 수 있습니다.
App state vs Ephemeral State
Flutter의 상태는 앱 상태와 임시 상태로 구분하여 관리해야 합니다.
Ephemeral state
일시적 상태(Ephemeral state)
는 단일 위젯에서 사용하는 상태입니다.
그러므로, 위젯 트리의 다른 위젯은 이 위젯의 상태에 대해 몰라도 되며, 직렬화할 필요 없고 복잡한 방식으로 변경되지 않습니다. 즉, 이 상태에는 상태 관리 라이브러리를 적용할 필요가 없고 setState()를 사용하면 됩니다.
App state
앱 상태(App state)
는 앱의 여러 화면에서 공유할 수 있는 일시적이지 않은 상태를 말합니다.
앱 상태가 필요한 경우를 예를 들면, 아래와 같습니다.
- 사용자 기본 설정
- 로그인 정보
- 소셜 네트워킹 앱의 알림
- 전자 상거래 앱에서의 장바구니 목록
- 뉴스 앱에서의 기사 읽음 / 읽지 않음
단일 위젯에서만 사용하는 상태일 경우는 상태 관리가 특별하게 관리되지 않아도 되지만, 앱의 여러 위젯에서 상태를 사용하는 경우에는 상태 관리가 매우 중요하게 됩니다.
예를 들면, 플러터로 앱을 만드는데 어떤 위젯이 존재하고 외부의 변화(네트워크 통신, 다른 위젯의 동작, System calll 등)로 인해서 해당 위젯의 상태를 변경하고 싶을 수 있습니다.
그런데 만약, App state를 사용하지 않고 다른 화면에서 해당 위젯의 state를 알고싶다거나 변경하고 싶어서 해당 위젯의 state를 매개변수를 통해 외부에서 가져온다거나 state를 전역변수로 빼거나 하면 아래와 같은 문제들이 발생할 수 있습니다.
1. Strongly coupling widgets
-> 매개변수로 위젯의 state를 가져오거나 하면 위젯 간의 강한 결합이 생기게 됩니다. 때문에, 앱이 커지면 커질 수록 복잡해지고 확장성에 매우 좋지 않게 됩니다.
2. Calling setState from outside
-> 매개변수를 통해 위젯의 상태를 외부에서 가져오게 되면 가져온 위젯의 상태를 외부에서 변경할텐데, 이 위젯의 상태를 사용하는 곳이 많으면 많을 수록 해당 위젯의 상태를 어디에서 변경하게 되는지 알기 어려워집니다.
3. Globally tracking state
-> 위젯의 상태를 전역적으로 빼내게 되면 당연하게도 Unit test를 하기가 어려워집니다.
Flutter에서는 이러한 App State 관리를 지원하는 InheritedWidget을 제공하고 있지만, 확장성이 좋지 않아 더 편하게 상태 관리를 하기 위해 다양한 접근 방법으로 상태 관리를 지원하는 라이브러리들이 만들어 졌습니다. 상태 관리 라이브러리는 Riverpod, Provider, BLoC, GetX 등의 여러 라이브러리들이 있는데 각자 장단점이 있으므로 비교해서 사용하면 좋을 것 같습니다.
References
Pragmatic State Management in Flutter (Google I/O'19)
https://docs.flutter.dev/data-and-backend/state-mgmt/intro