
MVVM이란
- Model + View + ViewModel 의 약자
- Model : 데이터를 서버 등에서 가지고 오는 계층
- JSON 예제에서 Human, Pet 클래스 — JSON에서 데이터를 가지고 오는 클래스
- 서버에서 데이터를 가지고 오는 경우에는 각 모델(데이터 클래스)별로
Repository를 만들어서 가지고와서 JSON을 객체로 변환해서 반환
- View : 화면을 구현하는 계층
- 위젯
- ViewModel : Model 계층(
Repository)에서 데이터(Model 클래스)를 가지고 와서 가공 및 상태 관리하는 계층
MVVM과 StatefulWidget 비교
StatefulWidget
사용자 클릭, 로직 처리
→ 데이터 요청해서 데이터 받음
→ 받은 데이터 가공 및 상태 업데이트
→ 화면 업데이트
⇒ StatefulWidget에서 많은 역할 수행 == 코드 지저분해짐.
MVVM 작동 원리
ViewModel 관찰 시작 (ViewModel의 상태가 변하는지 안 변하는지)
→ 사용자 클릭 = ViewModel에 처리 요청
→ 로직 처리
→ 데이터 요청해서 데이터 받음
→ 받은 데이터 가공 및 상태 업데이트
→ 자신의 상태가 바뀌었다고 알림 (View가 누군지는 모름)
→ View는 ViewModel을 구독하고 있기 때문에 상태가 바뀌었다는 것을 감지. 화면 업데이트.
얻게 되는 효과
- 각각 계층의 역할에 맞게 코드를 작성하기 때문에 코드가 깔끔해짐
- 유지보수 편해짐
- 오류발생 감소
- 중복코드 감소
- 각각 역할이 분리되어 있으니 각자 역할에 맞는 테스트 작성 가능
- 서로 결합도(View는 ViewModel을 참조하지만 ViewModel은 어떤 View가 참조하는지 모름)이 낮아져서 테스트 작성 용이
Flutter에서 MVVM 구현
- 상태관리 라이브러리 활용 :
RiverPod
RiverPod
- 상태관리 라이브러리
- ViewModel의 역할 (상태를 관리하고 변경되었음을 알려주는 역할)을 쉽게 구현 가능
- View(Widget)에서 ViewModel의 관찰을 쉽게 하게 해줌
사용법
ViewModel 만드는 법
- 관리할 데이터를 담을 상태 클래스를 만든다.
class HomeState {
int counter;
HomeState(this.counter);
}- Notifier를 상속받는 ViewModel class를 만든다.
// Notifier를 상속받으면 상태를 저장하고 업데이트할 수 있는 기능을 갖게 됨 (ViewModel의 구실 가능)
// Notifier 상속 시 이 ViewModel이 어떤 상태를 관리하는지 제너릭으로 지정
class HomeViewModel extends Notifier<HomeState> {
// Notifier 클래스의 build 메서드를 재정의 하여 초기 상태값 return 하기 => HomeViewModel이 생성되면 build 메서드의 리턴값으로 상태가 초기화
@override
HomeState build() {
return HomeState(1);
}
void updateState() {
// 상태를 업데이트 해줄 땐 새로운 객체를 만들어 변경
state = HomeState(state.counter +1);
//새로운 객체를 state에 할당하지 않으면 자신을 바라보는 View에게 상태가 변경되었다고 알리지 않음.
// state.counter++; // => X
}
}- ViewModel을 관리 및 공급해 줄 NotifierProvider 객체를 변수에 담아준다.
// 뷰에서는 이 공급자에게 ViewModel 달라고 요청. => 뷰모델 관리자
final homeViewModelProvider
// 이 뷰모델 관리자가 관리해야할 뷰모델의 타입과 뷰모델이 관리하는 상태 제너릭으로 명시
= NotifierProvider<HomeViewModel, HomeState>(
// 생성자에 뷰모델을 생성하는 함수를 넘겨줌
// 뷰에서 관리자에게 뷰모델 달라고 요청할 때 실행되어 뷰모델이 생성됨
// 단 기존에 생성이 되어있으면 기존에 생성된 걸 전달
(){
return HomeViewModel();
});Widget에서 사용법
- Consumer 위젯 사용
Consumer(
builder: (context, ref, child){
ref.watch(homeViewModelProvider);
return Column(children: [
Text()
]);
}
)- 뷰모델 관리자(공급자)가 뷰모델을 제공할 수 있게 최상위 위젯 ProviderScope로 감싸기
void main() {
// 이 앱에서 ViewModel을 RiverPod이 관리하게 해줌
runApp(const ProviderScope(child:MyApp()));
}Share article