Flutter 개발자들이 사용하는 상태관리 라이브러리는 대표적으로 Provider
, GetX
, Riverpod
, Bloc
이 있다. 이 중 많이 사용되는 아래 2가지의 라이브러리의 동작 방식 및 차이점을 정리해보자.
MVVM
패턴에서의 사용을 예시로 살펴보자.
// 주입 시
ChangeNotifierProvider(
create: (_) => ViewModel()
child: View()
);
// 사용 시
final ViewModel viewModel = Provider.of<ViewModel>(context);
final ViewModel viewModel = context.watch<ViewModel>(); // 위와 동일
viewModel.myFunc();
View
를 생성할 때 ChangeNotifierProvider
를 이용하여 사용할 ViewModel
을 주입한다.
// 주입 및 사용
final ViewModel viewModel = Get.put(ViewModel());
final ViewModel viewModel = Get.find<ViewModel>();
viewModel.myFunc();
Get.put()
을 이용하여 사용할 Viewmodel
을 주입한다.
주입 위치와 무관하게 전역으로 관리되므로 Get.find()
를 이용하여 어디서든 인스턴스를 사용할 수 있다.
class ProviderViewModel extends ChangeNotifier {
String name = '';
void setMyName() {
name = 'myname';
}
void printMyName() {
print(name);
}
}
class GetXViewModel extends ChangeNotifier {
RxString name = ''.obs;
void setMyName() {
name.value = 'myname';
}
void printMyName() {
print(name.value);
}
}
GetX
고유의 Rx
타입 변수로 선언하고, 초기화 값에 .obs
를 붙여 초기화 한다..value
를 붙여 값을 재할당 또는 사용한다.class ProviderViewModel extends ChangeNotifier {
String name = '';
void setMyName() {
name = 'myname';
notifyListeners();
}
}
ViewModel
내 상태 변수 변경 시 notifyListeners
를 이용하여 View
에 변경 여부를 알리게 되면 리빌드된다.
개발자가 리빌드 시점을 정할 수 있으므로 불필요한 리빌드를 줄일 수 있다.
// View
Obx(() {
...
return Widget();
});
Rx
타입으로 선언한 변수가 변경되면 View
에서 Obx
위젯으로 감싼 부분이 자동으로 리빌드된다.
하나라도 변경될 때마다 자동으로 리빌드가 진행되므로 불필요한 리빌드가 발생할 수도 있다.
// null
별도의 라우팅 기능을 제공하지 않는다.
Get.to(View());
Get.to()
를 이용하여 간편하게 화면을 전환할 수 있다.
// BuildContext 활용 주입
ChangeNotifierProvider(
create: (context) => ViewModel()
child: View()
);
// BuildContext 기반 접근
final ViewModel viewModel = Provider.of<ViewModel>(context);
ChangeNotifierProvider
, Provider
등으로 상태를 관리하며 Widget Tree
를 따라서 전달된다.
이 Widget Tree
내에서 BuildContext
를 기반으로 가장 가까운 상태를 찾고 접근하는 방식을 사용한다.
상태를 제공하는 범위를 명확하게 제한할 수 있지만, BuldContext
가 꼭 필요하다는 점과 상태를 가져오기 위해서는 트리를 탐색해야 한다는 점, 그리고 BuildContext
를 사용하기 때문에 비동기 작업에서의 주의가 필요하다는 점이 특징이다.
// BuildContext 불필요
final ViewModel viewModel = Get.put(ViewModel());
final ViewModel viewModel = Get.find<ViewModel>();
Get.to(View());
BuildContext
를 사용하지 않고 상태를 전역으로 관리할 수 있기 때문에 코드가 간결해지고 제한이 적다.
프로젝트 규모가 커질수록 의존성 충돌이 발생할 위험이 있다.
그럼 다음 게시글부터 MVVM 패턴으로 구현한 간단한 예제를 각 상태관리 라이브러리에 초점을 맞춰 살펴보면서 차이점을 이해해보자