We have the official docs showcasing an example of backwards write in Compose:
@Composable
fun BadComposable() {
var count by remember { mutableStateOf(0) }
// Causes recomposition on click
Button(onClick = { count++ }, Modifier.wrapContentSize()) {
Text("Recompose")
}
Text("$count")
count++ // Backwards write, writing to state after it has been read
}
It's clear to me that updating State
object inside a composable like that causes a backwards write.
The stated effect of this backwards write is that we end up with an infinite cycle of recompositions.
However, what's interesting is that the count++
increment action at the bottom of the composable doesn't trigger an infinite cycle of recompositions. Basically, on the first composition of BadComposable
, everything seems fine as there are no extra recompositions even though we've updated count
at the end of the body of BadComposable
.
If, however, you then press on the Button
, the count++
increment action inside the onClick
callback triggers an infinite cycle of recompositions.
Why do we have to press on the Button
to trigger an infinite cycle of recompositions?
I was expecting that it's enough to read a value and update it in the body of the composable to get such an effect.
Jorge Castillo (thank you for your help) has hinted that it may be because the first update of the count
state object happens before the initial recomposition scope of BadComposable
is registered.
Source for this idea.