UI Architecture Pattern - MVI#
Issues with MVC/MVVM/MV#
MVC/MVVM/MV all separate the View and Model, and the Model/ViewModel/StatefulModel needs to handle and save the state of the View. Therefore, when page interactions and component development become complex, it becomes difficult to ensure the consistency of the entire application's state.
What is MVI#
MVI stands for Model-View-Intent pattern. MVI divides the processing logic into three parts: Model, View, and Intent. The Model is responsible for handling data and business logic, the View is responsible for rendering the UI and user interactions, and the Intent is responsible for message passing. It encapsulates actions from user input, View events, Model state changes, etc. into Intents and sends them to the Model. After processing, the Model sends the Intents to the View for rendering. This approach ensures the consistency of the entire application's state and makes it easier to handle complex UI state synchronization issues.
View(Model(Intent()))
How is MVI different from MVC/MVVM/MV#
Compared to MVC/MVVM/MV, MVI focuses more on data flow and state management, emphasizing one-way data flow and the single source of truth principle. MVC/MVVM/MV can all be improved by adopting the data flow and state management ideas from MVI, making the application easier to maintain and extend. Therefore, MVI is not completely independent of MVC/MVVM/MV, but rather a deep practice and extension based on them.
Using MVI#
MVI uses a unified state to solve UI state consistency issues and uses Intent-Reducer-State one-way data flow to solve complex relationships between states.
selector : (state)->state
render : (state)
[View]
package ViewModel {
[UiState]
[UiIntent]
[Reducer]
}
[UiState] -up-> [View] : observe(selector,render)
[View] -down-> [UiIntent] : dispatch(intent)
[UiIntent] -down-> [Reducer]
[Reducer] -up-> [UiState] : reduce(intent,state) -> state
MVI and Composite Pattern#
In the MVI architecture, each UI component has its own independent State and Intent. These States and Intents are combined to form the overall State and Intent of the entire UI. This allows us to better manage UI states and user actions, with clearer code organization and higher maintainability. It also improves efficiency when developing large-scale applications.
class Page
class View1
class View2
class View1State
class View2State
class PageState
Page *-left- View1
Page *-right- View2
PageState *-left- View1State
PageState *-right- View2State
View1 -down-> View1State
View2 -down-> View2State
data class View1Intent
data class View2Intent
data class PageIntent{
View1(val state:View1State):PageIntent
View2(val state:View2State):PageIntent
}
fun dispatch(intent:PageIntent){
when(intent){
is View1 -> dispatch(View1.sate)
is View2 -> dispatch(View2.sate)
}
}