¿Cuál es la diferencia entre usar SideEffect y no usarlo en JetpackCompose?

Trato de entender SideEffect de Jetpack Compose.

Aparte del documento oficial, encuentro otras 3 referencias

Todavía estoy confundido. Mi pregunta simple como a continuación

¿Cuál es la diferencia si hago esto con SideEffect

var i = 0
@Composable
fun MyComposable(){
    Button(onClick = {}){
        Text(text = "Click")
    }
    SideEffect { i++ }
}

y sin SideEffect

var i = 0
@Composable
fun MyComposable(){
    Button(onClick = {}){
        Text(text = "Click")
    }
    i++
}

Ejemplo de código de https://www.section.io/engineering-education/side-effects-and-effects-handling-in-jetpack-compose/

¿Hay alguna forma de i++que todavía se active en un caso pero no en el otro? ¿Cómo puedo crear una forma de experimentar con eso?

Answer

La SideEffectfunción es un ámbito de código activado fuera de la función Compose. Encontré una manera de diferenciarlos.

Si lo ejecuto como se muestra a continuación

@Composable
fun TrySideEffect() {
    var timer by remember { mutableStateOf(0) }
    Box(contentAlignment = Alignment.Center) {
        Text("Time $timer")
    }

    Thread.sleep(1000)
    timer++
}

El código anterior solo mostrará 0. El timer++no tiene impacto, ya que se cambió mientras se componía, dado que es parte de la función componible.

Sin embargo, si usamos SideEffectcomo se muestra a continuación, dado que no es parte de la función de redacción, timer++activará esto, y esto hará que la función componible se recomponga una y otra vez (Dado SideEffectque se llama en cada componible). Esto hará que el Texto muestre 0, 1, 2, 3, 4...

@Composable
fun TrySideEffect() {
    var timer by remember { mutableStateOf(0) }
    Box(contentAlignment = Alignment.Center) {
        Text("Time $timer")
    }

    SideEffect {
        Thread.sleep(1000)
        timer++
    }
}

Información adicional

Para hacerlo un poco interesante, si pongo el siguiente código, el texto mostrará 0, 2, 4, 6... (dado que el primero ++timerocurrirá sin componer, y el ++timerque ocurra en el SideEffectlo activará)

@Composable
fun TrySideEffect() {
    var timer by remember { mutableStateOf(0) }
    Box(contentAlignment = Alignment.Center) {
        Text("Time $timer")
    }

    SideEffect {
        Thread.sleep(1000)
        timer++
    }

    Thread.sleep(1000)
    timer++
}

Otra nota interesante, comparando SideEffectconLaunchEffect

Si usamos LaunchEffect, el número solo se incrementará una vez, es decir, de 0 a 1. Esto se debe a que, a diferencia SideEffectde , LaunchEffectsolo se activa en la primera recomposición y no cambia en la siguiente recomposición (a menos que cambiemos el key1valor, por lo que se activará al cambiar de key1valor).

@Composable
fun TrySideEffect() {
    var timer by remember { mutableStateOf(0) }
    Box(contentAlignment = Alignment.Center) {
        Text("Time $timer")
    }

    LaunchEffect(key1 = Unit) {
        delay(1000) // or Thread.sleep(1000)
        timer++
    }
}