:wave: I am refactoring part of our app to use Co...
# compose
m
👋 I am refactoring part of our app to use Compose, and trying to reuse our MVI viewmodels which a property of
StateFlow
of different states. e.g.
Copy code
sealed class MyState{
   object Loading…
   class ShowList(val list:List<String> ) …
   class Itemselected( val item:String)...
   class Error( val message:String )…
}
and then on the content I want to display something like
Copy code
@Composable
    fun MyPage(viewModel: MyViewModel) {
        val state: MyState by viewModel.getStateFlow()
            .collectAsState(initial = MyState.Loading)
        Column {
            Header("Home")
            PageBody(state) 
        }
    }
@Composable
fun PageBody(state: ServiceHubHomeState) {
    when (state) {
        MyState.Loading -> Header("Loading")
        is MyState.ShowList ->
            ListHub(serviceItems = state.list) 
        is MyState.ItemSelected -> { // do something else
        }
    }
}
So now, when I use .collectAsState, everything works all-right, BUT, when I have already published a value of Showlist, and a list is rendered, if a new state comes, e.g ItemSelected of course the list is cleaned up. My question is, how do I keep the already rendered list between the next state transitions? I am sure I have to keep the state somewhere but cannot see it 😞
a
Loading
is a State, but
ShowList
and
ItemSelected
are not, they are events. You are mixing states and events. Your state flow should contain two states:
Loading
and
List
, and
ItemSelected
should be emitted by another event flow.
m
the ItemSelected is an example, but let’s say I want to keep the list already there, and additionally display something more, how do I keep the already rendered list? In a fragment, when observed like this, a new state of course wouldn’t trigger the UI rendering again, but just adapt to do what is the change. In compose everything would render again, so I think the whole MVI rendering is not exactly going to work in compose compared to simple android views.
a
The problem here is how you should organize your state. When you do it correctly, there will naturally be no problem like this. If your
ItemSelected
or whatever do not overwrite
List
state, it is surely not a state, or at least not a state at the same level with
List
.
👍 1
a
The presented
MyState
sealed class means that only one possible variant can be displayed at a time. If you need to display multiple things, they all should be part of the same state variant:
Copy code
sealed class MyState {
    object Loading
    class List
    class ListWithItemSelected
    class Error
}
or
Copy code
sealed class MyState {
    object Loading
    class List(val list: SomeType, val selectedItem: SomeOtherType? = null)
    class Error
}
🙌 3
m
this is what I was aiming to do but thought of a way to avoid it. Thank you all!