I'm trying to write some code to show why side eff...
# compose
j
I'm trying to write some code to show why side effects in composables are bad, but I can't get it to actually show buggy behaviour:
Copy code
val data = remember { mutableStateListOf("One", "Two", "Three") }
    var size = 0
    Column(Modifier.padding(8.dp), Arrangement.spacedBy(4.dp)) {
        while (size < data.size) {
            val index = size++
            Row(horizontalArrangement = Arrangement.spacedBy(4.dp), verticalAlignment = Alignment.CenterVertically) {
                Button({ data.removeAt(index) }) { Text("X") }
                Button({ data[index] += "!" }) { Text("!") }
                Text(data[index])
            }
        }

        Text("Size: $size")

        Button({ data += "New ${size + 1}" }) { Text("Add") }
    }
If I understand this correctly, the
size
variable should go out of sync and show incorrect values. But how do I actually trigger that bug? Adding to, removing from and changing single elements in the list all don't do it.
Trying an even simpler approach now:
Copy code
Column(Modifier.padding(8.dp), Arrangement.spacedBy(4.dp)) {
        println("Column")
        var total = 0
        Row {
            println("Row 1")
            var text by remember { mutableStateOf("") }
            Button( { text += "!" }) {
                println("Button 1")
                Text("!")
                total++
            }
            Text(text)
        }
        Row {
            println("Row 2")
            var text by remember { mutableStateOf("") }
            Button( { text += "!" }) {
                println("Button 2")
                Text("!")
                total++
            }
            Text(text)
        }
        Text("Rows: $total")
    }
Still doesn't show the bug, because for some reason every button click recomposes the column and both rows. That makes no sense to me
v
Your recomposition scope is the upper level function because Row and Column are both inline functions. So when you update your state
data
or
text
in the latter example, it will recompose the whole block.
😲 1
(And that's because you have
Text(text)
reading the state. Remove it and you won't see recompositions.)
j
Thanks @vide, I didn't know Row and Column (and Box, apparently) were inline functions. Can you make a suggestion on how to get the side-effect bug to show? Just removing
Text(text)
won't do it, then there are no recompositions at all, so the size won't ever change
v
Copy code
var count = 0
Button({ count += 1 }) { Text("Increment: $count") }
are you looking for something like this?
j
Basically, yes. Combining this with a properly updated state should demonstrate the problem nicely. I can manage that 🙂
v
If you want to make tighter recomposition scopes, just create new functions