Flutter에는 다양한 상태 관리 패키지가 있다.
- GetX: https://pub.dev/packages/get
- BLoC: https://pub.dev/packages/flutter_bloc
- MobX: https://pub.dev/packages/mobx
이 외에도 굉장히 다양하게 있는데 플러터 공식문서에도 잘 정리되어있다.
나는 페이스북을 통해 개발 관련 얘기를 많이 접하는 편인데, 구글 Flutter 한국 사용자 그룹에서 최근에 한 멤버가 사용중인 상태 관리 패키지를 설문한적이 있다. 콘텐츠를 직접 여기에 캡쳐해서 올릴수는 없으니, 글 작성 시점 기준으로 확인해보면
- GetX: 32%
- Provider: 18%
- BLoC: 14%
- RiverPod: 35%
- MobX: 1%
가 투표되어있다. 약 200명 가까이 투표를 했는데, 내가 처음 어떤 상태 관리 패키지를 사용해야할 지 고민할 때도 설문 결과와 비슷한 상황이었다.
React를 사용할 때는 별 고민없이 Redux를 사용했고, Vue를 사용할 때는 별 고민없이 Vuex를 사용했다. 앞 설문에서 알 수 있듯이 Flutter는 흔히 말하는 “대세” 패키지가 없었다.
어떤 분야건 입문자에게 많은 선택권이 있다는 건 확실히 적잖이 허들이다. 또 고집은 있어서 강의에서 사용한 패키지를 그대로 사용하긴 싫었다. 사용하더라도 “강의에서 써서..” 라는 이유로 쓰고 싶진 않았다.
그래서 검색하다보니 LINE 기술 블로그에 Provider, GetX, BLoC를 비교해놓은 글이 있었다.
굉장히 정리를 잘 해놓은 글이라, Flutter에서 상태 관리 패키지를 고민중이라면 많은 도움이 될 글이다.
내가 처음 사용했던 패키지는 GetX였다.
Flutter에 입문할 때 대부분 공감하겠지만, context가 꽤 거슬린다. 조금만 코드를 분리하거나 잘못 이해하여 사용하면 context를 주입할 수 없는 환경이 되어 원하는 기능을 개발 할 수 없다. 그런 면에서 GetX는 굉장히 쓰기 편하다. context를 관리를 알아서 해주기 때문에.
(오죽 하면 flutter get context 라고 검색하면 from outside 와 같은 키워드도 같이 나오고, 실제로 GlobalKey를 이용해서 해결하는 내용이 많다.)
그렇다면 GetX를 안쓰게 된 이유는 뭘까. 패키지 홈을 보면 The Three pillars라고 나와 있다. 상태 관리 뿐만 아니라 라우팅 관리와 의존성 관리까지 해준다는 것이다. 심지어 예제 코드를 보면
Get.snackbar("Hi", "message");
가 있다.
Flutter에 있는 snackbar를 쓴다면 대부분 알고 있듯이
const snackBar = SnackBar(
content: const Text('Hi'),
);
ScaffoldMessenger.of(context).showSnackBar(snackBar);
와 같이 작성해야 한다. 코드만 봐도 굉장히 깔끔해지고 편해보이지만 오히려 이런 부분 때문에 안쓰게 되었다.
상태 관리 외에 다른 부분에서 너무 패키지 의존도가 높아지는 것 같았고, 그렇다고 GetX를 쓰면서 이런 부분을 안쓰는 건 오히려 비효율처럼 느껴졌기 때문이다.
게다가 LINE 블로그에서 얘기하는 context의 의존성 주입의 중요성을 보고 공감하기도 했다.
그래서 Provider와 BLoC를 고민하다 BLoC를 선택했다. 개인적으로 MVVM을 제대로 활용해본적이 없기도 해서, VM이 거의 강제되는 BLoC를 사용해보기로 했다. LINE 블로그 글에서도 알 수 있듯이, 실제로 코드량이 많아지기도 하지만 오히려 프로젝트의 각 디렉토리에 기대한 구조대로 구성이 되니 코드가 훨씬 구조화 된 것 같다.
(Provider로도 비슷하게 하지 않았을까 싶긴하다.)
그리고 가장 중요한 것이 있다. 웹에 LocalStorage가 있듯이 앱에도 저장소가 있다. DB도 있고, Key-Value 스토리지도 있는데, BLoC는 각 상태를 저장소와 매핑 시켜 별도의 저장,로드 구조 인터페이스 없이 앱에 저장되는 상태를 만들 수 있다. 기본 패키지가 지원하는 건 아니지만, 다른 패키지를 통해서 공식 지원하고 있다.
- hydrated_bloc: https://pub.dev/packages/hydrated_bloc
예를 들어 복잡한 필터를 가진 검색기능을 만드는데, 이 필터가 앱 재실행시 필터를 유지하고자 할 때 위 hydrated_bloc 패키지를 사용한다면, 앱의 생명주기에 따라 저장/불러오기 과정이 있어야 하는데 그런 로직이 필요없다.
사실 이부분이 가장 컸던 것 같다. 물론 원하는 구조를 만들수 없다면 고려조차 안했겠지만, 러닝커브를 극복할만큼 매력적인 기능이었다.
개인적으로 Flutter의 상태 관리 패키지는 하나의 정답은 없지만, “대세”가 몇개 있는 것 같다.
그런 관점에서, 기존에 익숙한 상태 관리 패키지가 있는 것이 아니라면 BLoC가 좋은 선택일 것 같다