Maybe a stupid question, but is it possible to hav...
# compose
o
Maybe a stupid question, but is it possible to have a
map
function on
SnapshotStateList
instance that would be itself
state list
(but not mutable), so that it only calls map’s lambda when original list changes? Kinda like
val files = mutableStateListOf("/path/to/file1", "/path/to/file2"); val loadedFiles = files.map { loadFile(it) }
and so that it calls
loadFile
only on inserted/modified elements of
files
.
d
Not sure if I get it right. Out of my head something like the below with a combination of
derivedStateOf
and
toMutableStateList
could work. It's still a mutable state list, but should change when the files state list changes.
Copy code
val files = remember { mutableStateListOf("/path/to/file1", "/path/to/file2") }

val loadedFile = remember {
    derivedStateOf {
        files.map { path ->
            File(path)
        }
    }.value.toMutableStateList()
}
o
Nope, it will rebuild the whole loadedFile list once any change occurs in the source mutable state list, because
map
there is just an ordinary collection function.
z
You could make a List implementation that delegates to your state list and does the mapping on access.
o
@Zach Klippenstein (he/him) [MOD] but I want it to be a state, i.e. memoized
Kinda like derived state, but for a collection per item
z
Sure:
Copy code
val loadedFile = remember(files) { MappingList(files) { doTransform(it) } }
Copy code
class MappingList<I, O>(
  private val source: SnapshotStateList<I>,
  private val transform: (I) -> O
): List<O> {
  override val size get() = source.size

  override fun get(i: Int) = transform(source[i])

  // etc
}
o
Hm, let me try to explain what I want differently, probably I was not clear enough 🙂 Given a
SnapshotStateList<T>
as a source, I would like to synchronize it to another
SnapshotStateList<R>
with a transformation function
T->R
. So that if an item is added to the source, the transformation function is called just once on the new value and it is placed in the target. If the item is removed, it is removed from both lists (by index, since they are synced). If the item is updated, the transformation function is called and value is replaced at target by index again.
z
You can keep an internal list of derived states for individual transform results, but keeping it trimmed might be kind of hacky (do it on each read?)
A less hacky option might be to just use an explicit PersistentList and then clear the cache each time you get a new list instance. But requires depending on kotlinx.collections.immutable yourself, which isn’t an option if you’re writing a library.
m
JavaFX has this built in, you could look at their code for inspiration: https://openjfx.io/javadoc/18/javafx.base/javafx/collections/transformation/package-summary.html