What's the different using SideEffect and not using it in JetpackCompose?
I try to understand SideEffect of Jetpack Compose.
Other than the official document, I find 3 other reference
- https://jorgecastillo.dev/jetpack-compose-effect-handlers
- https://www.section.io/engineering-education/side-effects-and-effects-handling-in-jetpack-compose/
- https://medium.com/@umairkhalid786/jetpack-compose-side-effects-sideeffect-1e9995b6d423
I'm am still confused. My simple question as below
What's the difference if I do this with SideEffect
var i = 0
@Composable
fun MyComposable(){
Button(onClick = {}){
Text(text = "Click")
}
SideEffect { i++ }
}
and without SideEffect
var i = 0
@Composable
fun MyComposable(){
Button(onClick = {}){
Text(text = "Click")
}
i++
}
Code example from https://www.section.io/engineering-education/side-effects-and-effects-handling-in-jetpack-compose/
Is there a way the i++
is still triggered in one case but not the other?
How can I create a way to experiment with that?
Solution 1:
The SideEffect
function is a scope of code triggered outside of the Compose Function. I found a way to differentiate them.
If I run it as below
@Composable
fun TrySideEffect() {
var timer by remember { mutableStateOf(0) }
Box(contentAlignment = Alignment.Center) {
Text("Time $timer")
}
Thread.sleep(1000)
timer++
}
The above code will only show 0
. The timer++
has no impact, as it was changed while it is being composed, given it's part of the composable function.
However, if we use SideEffect
as shown below, given it is not part of the compose function, the timer++
will trigger this, and this will make the composable function recompose again and again (Given SideEffect
is being called on each Composable). This will make the Text show 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++
}
}
Additional Info
To make it a little interesting, if I put on the below code, then the text will display 0, 2, 4, 6 ... (given the first ++timer
will happen without composing, and the ++timer
that happen in the SideEffect
will trigger it)
@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++
}
Another interesting note, comparing SideEffect
with LaunchEffect
If we use LaunchEffect
, the number will only increment once, i.e. from 0 to 1. This is because unlike SideEffect
, LaunchEffect
only triggered on the first recomposition, and not change on the subsequent recomposition (unless we change the key1
value, so it will be triggered upon change of key1
value.).
@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++
}
}