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

krzysztof

06/09/2022, 9:03 AM
What would be the best way to react to
mutableStateListOf
changes in effects? Say, I have
Parent
which has state
remember { mutableStateListOf<Int>() }
which can be changed by one of its children.
Parent
also has an effect (let’s say
DisposableEffect
) reading changes to the list, like
DisposableEffect(list){/* ... */}
. But that effect won’t be called more than once, because
list
won’t change instance (
SnapshotStateList
), even if items are added.
s

ste

06/09/2022, 11:16 AM
You could: 1- Pass a parameter down the tree
onListChanged: () -> Unit
to let the children notify the parent when it modifies the list; 2- Use
list.size
as key instead of
size
, however I'm not sure how it would react when swapping two elements; 3- Depends on your use case
s

SaurabhS

06/09/2022, 1:00 PM
You could use
snapshotFlow()
. It should emit when the list is updated.
☝🏻 1
z

Zach Klippenstein (he/him) [MOD]

06/09/2022, 3:17 PM
Yep this is precisely what
snapshotFlow
is for. Or any of the lower-level apis for snapshot observation.
k

krzysztof

06/09/2022, 3:20 PM
so having this in
Copy code
val list = remember { mutableStateListOf<Int>() }

  LaunchedEffect(Unit) {
    snapshotFlow { list }.collect {
      Log.i("XXX", "snapshot updated!")
    }
  }
and then calling
Copy code
list.add(2)
should print
snapshot updated!
, correct?
z

Zach Klippenstein (he/him) [MOD]

06/09/2022, 3:29 PM
I think so. I can't remember off the top of my head if the flow will dedup emits because the list identity is the same - but if you move the log call into the snapshotFlow block and just use an empty collect it should definitely do that.
k

krzysztof

06/09/2022, 3:39 PM
That was my first thought too about
snapshotFlow { list }
, to be updated whenever the list is modified. But it’s not the case here. If I do
snapshotFlow { list.size }
then it’s working as expected. Like you said,
list
has the same identity (due to remember)
z

Zach Klippenstein (he/him) [MOD]

06/09/2022, 3:43 PM
Right, so a cool trick about snapshotFlow is that you don't actually have to use it as a flow. You can just use it to create a restartable function by doing all your work in the snapshotFlow lambda and just ignoring the emitted values with an empty collect.
👍 1
k

krzysztof

06/09/2022, 3:52 PM
Cool, nice trick 😄
Copy code
LaunchedEffect(Unit) {
    snapshotFlow { Log.i("XXX", "list size: ${list.size}") }.collect {}
  }
My main problem is that, I pass my
mutableListStateOf
down to children (as List<T>) and in there, I have
LaunchEffect(list)
call, which is not re-executed when list is updated.I’ll have to find different way then
z

Zach Klippenstein (he/him) [MOD]

06/09/2022, 3:59 PM
It would be helpful to know more about your code to figure out what the best overall solution is, but you actually still want to pass the list as a key (since if the identity of the list changes, you need to restart the effect), but you probably want to combine them:
Copy code
@Composable fun Foo(list: List<T>) {
Copy code
LaunchedEffect(list) {
    snapshotFlow { list.… }.collect()
  }
}
(FYI There’s a collect override that doesn’t take any params that’s good for this use case)
🙌 1
k

krzysztof

06/10/2022, 8:17 AM
I have
DisposableEffect
that should listen for changes in
list
, and that effect does not own coroutine scope, so it’s bit tricker
(FYI There’s a collect override that doesn’t take any params that’s good for this use case)
Yup, found it, has to be exported as it’s extension 👌
z

Zach Klippenstein (he/him) [MOD]

06/10/2022, 4:20 PM
So just change it to a LaunchedEffect
k

krzysztof

06/10/2022, 7:31 PM
Can’t really, there needs to be some cleanup done when
list
changes 😄
z

Zach Klippenstein (he/him) [MOD]

06/10/2022, 9:23 PM
You can do that with a launched effect. Anything you can do with disposable effect you can do with a LaunchedEffect
k

krzysztof

06/12/2022, 6:42 PM
Do you mind explaining this/show an example?
DisposableEffect has
onDisposed
called, so my guess for LaunchedEffect would be doing a cleanup when its coroutine is cancelled?
z

Zach Klippenstein (he/him) [MOD]

06/13/2022, 3:31 PM
Exactly
👌 1
221 Views