Hi! I'm triying to build a TodoApp with the MVI pa...
# compose
c
Hi! I'm triying to build a TodoApp with the MVI pattern. 🧵
same 1
For me each screen have is own Store, and each Store hold is own State
Copy code
sealed class State
object Error : State()
object Loading : State()
data class Success(
    val tasks: Tasks,
    val input: String,
) : State()
Some people maybe have a unique store with the entire State application.
The store looks like this:
Copy code
class Store() : ViewModel() {
    val state: MutableStateFlow<State> = MutableStateFlow(Loading)

    fun Action.reduce(currentState: State): State =
        when (this) {
            is LoadTasks -> //copy of success state
            is ChangeInput -> //copy of success - val input: String,
            is AddTask -> //copy of success -  val tasks: Tasks,

    fun action(action: Action) {
        state.value = action.reduce(state.value)
    }
}
and the Compose App is something like that:
Copy code
setContent {
   val s by store.state.collectAsState()
   when (val state = s) {
       is Error -> Column {
          Text(text = "Error")
          Button(onClick = { store.action(LoadTasks) }) {
               Text(text = "Reload")
             }
           }
        is Loading -> Text(text = "Loading")
        is Success ->
            Column {
               Log.e("render", "Column")
               Row {
                  Log.e("render", "Row")
                  TextField(
                       value = state.input,
                       onValueChange = { store.action(ChangeInput(it)) }
                  )
                  Button(onClick = { store.action(AddTask(state.input)) }) {
                        Log.e("render", "Button")
                        Text(text = "Add")
                  }
                  Row {
                     Log.e("render", "Row2")
                     Row {
                        Log.e("render", "Row3")
                     }
                  }
             }
             LazyColumn {
                items(state.tasks.tasks) { task ->
                   Text(text = task.task)
                }
                         }
            }
each time that I enter a letter in the TexField, a recomposition of all Composable occurs, this makes sense.
How could I update the TextField and the Button only?
since I'm just making a copy of the 
state.input
d
You could make input a
MutableState<String>
And have your store mutate it.
But personally I don't believe MVI is a really good fit for Compose. MVI will cause performance and other odd behavior due to how Compose computes it's new UI.
Compose is best at detecting mutations in the data you set and updating only what changed. But emitting a gigantic screen state each time makes it harder for Compose to do its thing.
Compose was designed to work best with MutableState<T> classes, it would be wise IMHO to use those.
MVI tries to force a system that is a good marriage between OOP and FP into a FP box. In my experience this is not a wise idea.
c
With this little experiment i try to see the pro and cons of this pattern, if the most efficient solution is wrap my objets with MutableState<T>, i think that i prefer not to use MVI 😆
MutableState <T> is an implementation detail and I think that my store shouldn't matter if I use Compose or React
i really appreciate your opinion
d
I have another solution that kind of acts as an adapter between the two worlds, Store and Compose, but honestly it's just going to add more work to maintain. But if you're interested I would be happy to code up an example for you.
c
If you have a free time I will be happy to see that solution 😀
it isn't because I finally used it, but more in order to learn and understand even further about the problem