카테고리 없음

Flutter MVVM & Riverpod 심화 이해 (2025.11.06)

kwontete 2025. 11. 6. 20:55

MVVM 구조 복습

  • Model: 데이터를 정의하는 구조체.
    → JSON, API, DB 등 외부 데이터의 형태를 정의하고, 변환 로직(fromJson, toJson)을 포함.
  • Repository: 데이터를 “어디서 가져올지” 관리하는 역할.
    → 예: Firestore, REST API, Local DB 등과 통신하고, 받은 데이터를 Model로 변환.
  • ViewModel: Repository로부터 데이터를 받아 state를 변경하고, View(UI)에 반영되도록 함.
  • View(UI): ref.watch()를 통해 상태 변화를 감지하고 자동으로 다시 빌드.

요약

Model은 “데이터 구조”, Repository는 “데이터 출처”, ViewModel은 “상태 관리”, View는 “표현 담당”.


state.count.count의 의미

  • state → HomeState 객체
  • state.count → Count 클래스 객체
  • state.count.count → 실제 숫자 값 (int)
    즉, 이중 구조 때문에 이렇게 접근하게 되는 것.

개선 방법: Count 클래스의 필드명을 value로 변경
→ state.count.value 로 간결하고 직관적으로 표현 가능.


Future의 필요성

  • 현재 incrementCounter()는 단순히 숫자 더하기이므로 비동기(Future, async/await) 불필요.
  • Future는 Repository처럼 서버 통신(DB, API 등)에서만 사용해야 함.

수정 전

Future<void> incrementCounter() async { final counter = await state.count.count; state = HomeState(Count(counter + 1)); }

 

수정 후

void incrementCounter() { final counter = state.count.value; state = HomeState(Count(counter + 1)); }


ConsumerWidget vs ConsumerStatefulWidget

구분설명사용 시점
ConsumerWidget Riverpod 상태만 구독. ref.watch 가능 단순 상태 UI
ConsumerStatefulWidget Riverpod + initState, dispose 같이 사용 가능 TextController, Animation 등 필요할 때
StatefulWidget setState()로 직접 UI 갱신 Riverpod 안 쓸 때만

결론

Riverpod에서는 ConsumerWidget이 기본,
UI 내부 컨트롤러가 필요할 때만 ConsumerStatefulWidget 사용.


NotifierProvider 선언 방식

  • Riverpod 3.0.3 버전에서는 다음과 같이 선언해야 함 👇
 
final homeViewModelProvider = NotifierProvider<HomeViewModel, HomeState>(HomeViewModel.new);
  • .new 생성자 참조 방식을 써야 최신 문법과 호환됨.
  • 변수명은 lowerCamelCase (homeViewModelProvider) 형식으로 선언.

StatefulWidget이 불필요한 이유

  • Riverpod은 상태 변화를 자동 감지하여 rebuild하기 때문에
    → setState()나 StatefulWidget이 필요 없음.
  • 대신 ViewModel(Notifier)에서 상태를 바꾸고, View는 ref.watch()로 반응.

오늘 배운 핵심 3줄 정리

  1. MVVM 구조 핵심: Model(데이터) → Repository(출처) → ViewModel(상태) → View(UI).
  2. Future는 비동기 로직일 때만, 단순 로직엔 불필요.
  3. Riverpod은 setState()를 대체하며, 대부분의 화면은 ConsumerWidget으로 충분하다.