How to use a mutableStateList / mutableStateMap as...
# compose
a
How to use a mutableStateList / mutableStateMap as a key for remember or side effect? or you just shouldn't try? We have a number of places with a mutableStateMap in a viewmodel, that gets exposed as just a Map<> to the consumer. If someone tries to do something like remember(map) { // create something base on map }, it doesn't get invalidated when changes to the map are made.
Here's more of an example:
Copy code
class VM ... {
    val componentMap: Map<String, Component>
        get() = _componentMap
    private val _componentMap = mutableStateMapOf<String, Component>()
}

@Composable
fun UsingMap() {
    val vm = viewModels<VM>()
    val componentMap = vm.componentMap
    val filteredMap = remember(componentMap) {
        componentMap.values.filterIsInstance<FooComponent>()
    }
    filteredMap.forEach{
        //
    }
}
Doing this instead works:
Copy code
// Works, only way?
    val filteredMap by remember {
        derivedStateOf {            componentMap.values.filterIsInstance<FooComponent>()
        }
    }
Which solves the remember case. Not sure about an Effect
a
There’s nothing wrong with it directly, but it depends on the behavior you want.
remember
,
key
and the effects use
.equals
to determine if the argument(s) have changed, and
.equals
is different than being
@Stable
and being observable for snapshot state For arguments that are mutable,
.equals
must return
true
for the same instance, so
remember
will only run once for the same instance.
LazyListState
is a good example where that is useful:
Copy code
LaunchedEffect(lazyListState) {
    snapshotFlow { lazyListState.layoutInfo.totalItemsCount }
        .collect {
            // use the new items count
        }
}
The
LaunchedEffect
here will restart whenever the instance of
LazyListState
changes. But then the internal properties of
LazyListState
can themselves change and we can observe them with
snapshotFlow
. So something else you could try is
remember(componentMap.toMap())
which creates an immutable copy to compare against for
.equals
a
yeah I was thinking .toMap() maybe another alternative once we move to Compose 1.4 and toMap won't always make a new copy. snapshotFlow is a good reminder too will try that out