https://kotlinlang.org logo
Title
c

CLOVIS

04/15/2023, 4:00 PM
This is going to sound very obvious, but I've always struggled with
collectAsState
… Assuming a function
fun foo(id: Int) = flow {
    expensiveNetworkRequest(id)
}.flowOn(<http://Dispatchers.IO|Dispatchers.IO>)
What is the correct way to collect it as state?
@Composable
fun Foo(id: Int) {
    // BAD: a new flow is created on each composition, leading to a recomposition loop
    val result1 by foo(id).collectAsState()

    // BAD: seems to also create a recomposition loop
    val result2 by remember(id) { foo(id) }.collectAsState()

    // GOOD?
    val result3 by remember(id) { foo(id).collectAsState() }

    Text(resultX)
}
c

Chris Fillmore

04/15/2023, 4:05 PM
Is there a reason you need to call foo in this Composable? Why not put it in a VM and pass the state in?
c

CLOVIS

04/15/2023, 4:06 PM
ViewModel is Android-only, right?
c

Chris Fillmore

04/15/2023, 4:18 PM
Android has a ViewModel class yes, but the concept applies generally
c

CLOVIS

04/15/2023, 4:18 PM
How would you write this example in a multiplatform way?
m

myanmarking

04/15/2023, 4:25 PM
result2
should be fine. What you say is a ‘recomposition loop’ is probably recomposition due to state emission
just log the function and check only one call per id
you are remembering the flow as long as it is the same id - and transforming the flow to a State<V>. It is perfectly fine i think
if the id changes, you want to collect from the new flow. so remember will call the function again and re-collect
from what i understand of your code, thats exactly what you need
c

CLOVIS

04/15/2023, 4:51 PM
That's indeed what I want, but last time I tried it looped infinitely 🤔
m

myanmarking

04/15/2023, 4:52 PM
if you are using ‘result2’, it can only loop ‘indefinitely’ if the key changes indefinitely
c

CLOVIS

04/15/2023, 4:53 PM
I'll try again and check how it works. Thanks
m

myanmarking

04/15/2023, 4:53 PM
if you want to make sure, just copy the ‘collectAsState’ function, and place a log inside the produceState block
you will check it is only called once for each id
l

leandro

04/15/2023, 7:59 PM
val result by produceState(initialValue) {
foo(id).collect { value = it }
}
m

myanmarking

04/15/2023, 8:02 PM
Thats what collectAsState do