https://kotlinlang.org logo
#compose
Title
# compose
j

jaqxues

02/22/2021, 4:26 PM
How would you ideally represent an observable list of data, where each element also has a state that can be updated. In case a single element updates its state, the list state should ideally not be updated to avoid unnecessary recomposition, etc I suppose you can do better than a
mutableStateListOf<StateFlow<StateFulData>>()
or similar?
o

Orhan Tozan

02/22/2021, 4:55 PM
I personally would avoid
mutableStateListOf<T>
in favour of
mutableStateOf<List<T>
for the same reason I would avoid
val list: MutableList<T>
in favour of
var list: List<T>
. Then, everytime a single element updates its state, you need to create a new list with the updated element and do
currentStateList = newList
j

jaqxues

02/22/2021, 4:58 PM
Yeah but there is UI state associated to the element that i could not keep if i would generate an entirely new list. Think of it has an item that can be expanded. If you just give it a new list, the expanded state would be reset for each element, even if its not the element with updated state --> bad ux
o

Orhan Tozan

02/22/2021, 5:01 PM
Does your list own the state of whether an item is expanded?
Either way, your list should know which item(s) is/are currently expanded, then you can just copy the list when you are updating an element so that you can still secure the expanded state.
j

jaqxues

02/22/2021, 5:06 PM
I do not want to go this route. There are advantages to immutable lists etc, but this creates more problems than it solves, at least imo
o

Orhan Tozan

02/22/2021, 5:12 PM
Alternative is that you could keep your mutabeStateListOf and introduce a seperate state, something like var expandedItemId: Int = ...
j

jaqxues

02/22/2021, 5:15 PM
That would still trigger recomposition for the entire list an everything, not a fan
o

Orhan Tozan

02/22/2021, 5:18 PM
You mean you expect Compose not being smart enough to just rerender the changed part?
j

jaqxues

02/22/2021, 5:19 PM
I want to keep the Composables alive so it doesnt have to reinitialize all the states, and I do not at all think that having a list of states would be a good idea by any stretch of the imagination.
o

Orhan Tozan

02/22/2021, 5:22 PM
I think you are going too technical and not embracing Compose's declarative advantage. Thinking about initialization of UI is still part of the old imperative style of UI programming
Compose should take care of the performance. Don't think about efficient UI mutation, just tell Compose what your new desired UI is, and Compose should be able to efficiently handle it.
j

jaqxues

02/22/2021, 5:29 PM
Oh i know how compose works... But having a list of expandedItems sounds terrible by architecture. Having an immutablelist that recomposes everything means losing local state such as isExpanded etc
o

Orhan Tozan

02/22/2021, 5:32 PM
Could you show some code? I'm not fully following what kind of list / UI we are talking about
j

jaqxues

02/22/2021, 7:06 PM
I suppose this code example would show what I need
Copy code
sealed class StatefulData {
    class Stage1(val msg: String): StatefulData()
    class Stage2(val t: Throwable): StatefulData()
}
@Composable
fun StateExample() {
    val list = mutableStateListOf<StateFlow<StatefulData>>()
    list.forEach {
        var (extended, setExtended) = remember { mutableStateOf(false) }
        Card(Modifier.toggleable(extended, onValueChange = setExtended)) {
            Column {

// Collecting as state: when the StateFlow for a single element updates, a single element is recomposed, 
// without losing the associated extended state

                when (val el = it.collectAsState().value) {
                    is StatefulData.Stage1 -> {
                        Text(el.msg, color = Color.Green)
                    }
                    is StatefulData.Stage2 -> {
                        Text(el.t.message ?: "No Error Message", color = Color.Red)
                    }
                }

                AnimatedVisibility(visible = extended) {
                    Text("Showing information in more detail")
                }
            }
        }
    }
}
o

Orhan Tozan

02/22/2021, 7:51 PM
Flow inside state is a no-go
j

jaqxues

02/22/2021, 7:52 PM
Yes, that is my feeling too, but I don't see anything better
o

Orhan Tozan

02/22/2021, 7:52 PM
Embrace the immutable path
j

jaqxues

02/22/2021, 7:53 PM
... then I will have to map
extended
states to elements in some way, that is also terrible
o

Orhan Tozan

02/22/2021, 7:54 PM
It isn't, it's just you specifying / being explicit in what is extended or not
j

jaqxues

02/22/2021, 7:55 PM
and managing those states / syncing these states? Not a fan... Not like my idea is better
o

Orhan Tozan

02/22/2021, 7:56 PM
You don't need to sync state. Syncing state is an anti pattern by itself.
j

jaqxues

02/22/2021, 7:56 PM
how would you keep track of what is extended?
o

Orhan Tozan

02/22/2021, 8:02 PM
Move the isExtended state to the root of the Composable, and make it extendedId, or extendedIds if its possible for multiple cards to be expanded at the same time
j

jaqxues

02/22/2021, 8:07 PM
well,, that is syncing state though.... Removing states if tey disappear, adding states when they appear
o

Orhan Tozan

02/22/2021, 8:07 PM
Could you elaborate?