MVI 정리
MVI 패턴이란?
단방향 데이터 흐름을 통해 상태를 관리하는 패턴
(일반적으로 단일 상태 사용!)
- Model : 상태 담당
- View : 사용자 이벤트를 Intent로 전달, 모델에서 받은 상태를 기반으로 화면 업데이트
- Intent : 사용자 액션이나 이벤트 정의, 사용자 이벤트를 받아 모델로 전달하여 상태 업데이트
단방향 동작
1. 이벤트 발생 (view -> intent)
2. 모델의 상태 변경 (intent -> model)
3. 변경된 상태로 Ui 업데이트 (model -> view)
어떻게 구현할까?
State : 상태는 가장 최신 값으로 유지할 수 있는 StateFlow
Event : 이벤트는 구독자가 없으면 무시할 필요가 있기 때문에 SharedFlow
Effect : 에러, 토스트와 같은 사이드이펙트는 한번만 보여주면 되기 때문에 Channel
⭐️ 이벤트를 처리할 때, 바로 뷰모델의 함수를 호출하는 것이 아니라 SharedFlow로 사용하는 이유는?
- 발생하는 이벤트의 구독자가 없다면 이벤트가 무시되어야함
- 여러개 뷰모델 사용할 경우에 각 이벤트 별로 뷰모델에서 처리할 동작이 다를수도 있기 때문에 BaseViewModel에서 flow로 처리
MVI 장점
- 앱 상태 예측 가능
- 단방향 데이터 흐름을 통해 상태 변화가 명확해져 상태 관리가 쉬움
- 상태를 필요로할 때 저장하고 다시 불러올 때 동일한 상태를 쉽게 재현할 수 있음
- 비동기 작업 시 성공과 실패 상태를 구분하여 상태를 명확하게 관리할 수 있음
MVI 단점
- 상태 기반 Ui를 위해 초기에 Intent, State 등 정의할 코드가 많음 -> 라이브러리로 해결 가능 ex) orbit, mavericks
- 상태는 불변 객체이기 때문에 상태가 변할 때 마다 객체가 새로 생성되기 때문에 메모리 사용량이 증가
-> 자주 변경되는 스크롤 위치 같은건 State에 포함시키기보다는 Ui 요소 내에서 관리
-> 자주 변경되는 값은 별도로 관리하거나 debounce로 업데이트 주기 줄이기
MVVM과 비교
- MVVM
- 여러 상태를 각각 독립적으로 StateFlow 형태로 가짐
- 여러 상태가 동시에 업데이트될 때 의도하지 않은 순서로 완료될 수 있고, 일관성 유지 어려움
- MVI :
- 단일 상태를 가짐. 여러개 값이 하나의 State로 이 객체의 최신값이 뷰에 반영됨
- 모든 이벤트가 인텐트로 시작되고 State로 완료되므로, 상태는 항상 특정 인텐트의 결과로 명확함
- 여러 이벤트가 동시에 발생해도 최종 상태만 뷰에 전달
MVI, 그래서 왜 사용하는걸까?
최근 리액트, 컴포즈 등 상태 기반 Ui 시스템이 대중화되면서 명확하고 예측 가능한 상태 관리가 중요해짐
비동기 작업에서 데이터 흐름에 따른 상태 업데이트를 명확하게 하기 위해 사용