Side effect is retaining old value from returned c...
# compose
d
Side effect is retaining old value from returned composable is this expected? and how to avoid this?
Copy code
@Composable
fun foo(): Int {
    var counter by mutableStateOf(0)
    LaunchedEffect(Unit) {
        while (true) {
            delay(500)
            counter++
            println("Foo: $counter")
        }
    }
    return counter
}

@Composable
fun bar() {
    val foo = foo()
    LaunchedEffect(Unit) {
        while (true) {
            delay(500)
            println("Bar: $foo")
        }
    }
}
Output in thread, but the the second composable will always returns: "Bar: 0"
Copy code
Foo: 1
Bar: 0
Foo: 2
Bar: 0
Foo: 3
Bar: 0
Foo: 4
Bar: 0
Foo: 5
Bar: 0
Foo: 6
Bar: 0
b
I suspect it is related with the key of your
LaunchedEffect
you’re missing a remember….
isn’t it so?
var counter by mutableStateOf(0)
=>
var counter by remember { mutableStateOf(0) }
d
oh your're correct, but why my key need to be changed? If I have long running effect that shouldn't be canceled, it will be canceled when the key change, how to workaround this?
o
I am not sure what are you trying to achieve, but could you return
State<Int>
from the
foo()
method? Also I would change
bar()
method a bit 🤔
Copy code
@Composable
fun foo(): State<Int> {
    val counter = remember { mutableStateOf(0) }
    LaunchedEffect(Unit) {
        while (true) {
            delay(500)
            counter.value++
            println("Foo: ${counter.value}")
        }
    }
    return counter
}

@Composable
fun bar() {
    val foo = foo()
    LaunchedEffect(foo) {
        println("Bar: $foo")
    }
}
d
@Oleksandr Balan does that make a difference? I have this code, where there's 1 flow that listening to user event. When
event.submit
it's running a long running operation. It using
couponState
value which in the long running operation logic. However if I I put that in the key, there's a change that the
submit
coroutines is canceled because the LaunchedEffect is restarted
Copy code
@Composable
    fun couponStatePresenter(event: Flow<Event>) {
        ...
    }

    @Composable
    override fun present(event: Flow<Event>): UIState {
        ...
        val couponState = couponStatePresenter(couponEvent)

        var submitResult: UIState.SubmitResult by remember { mutableStateOf(UIState.SubmitResult.Idle) }
        LaunchedEffect(Unit) {
            event.collect {
                when (it) {
                    is Event.Submit -> {
                        submitResult = UIState.SubmitResult.Submitting

                        if (!it.forceSubmit) {
                            if (couponState.isValidationFailed) {
                                submitResult = UIState.SubmitResult.RequireUserActionDialog(
                                    "Invalid Coupon",
                                    "Your coupon is invalid, do you want to clear and continue the booking?",
                                    actionPrimary = "YES"
                                )
                                return@collect
                            }
                        }

                        delay(2000) // Pretend API Call
                        submitResult = UIState.SubmitResult.Success
                    }
                    ...
                }
            }
        }
        ...
    }
b
the flow event should be part of the key as well
d
@Benoit Quenaudon but it never changes? Sure i think adding it won't hurt. Thanks