JetBrains / compose-multiplatform

Compose Multiplatform, a modern UI framework for Kotlin that makes building performant and beautiful user interfaces easy and enjoyable.
https://jetbrains.com/lp/compose-multiplatform
Apache License 2.0
15.24k stars 1.11k forks source link

Recomposition happens when Compose code comes from a dependency module #4967

Open bitspittle opened 1 week ago

bitspittle commented 1 week ago

Please check out this project which demonstrates the issue:

https://github.com/DennisTsar/bug-reports/tree/kotlin/compose/recomposition-1

Copying the README from that project here:


Compose 1.6.0+ Recomposition Issue

bitspittle commented 1 week ago

Just to emphasize how problematic this bug potentially is, I added the following code to my local project (a web project built using Kobweb):

var msg by remember { mutableStateOf("") }
TextInput(msg, onTextChanged = { msg = it }, ...)

// Sibling element which should NOT be affected by text input changes
Row(horizontalArrangement = Arrangement.spacedBy(10.px)) {
    var recomposeCount by remember { mutableStateOf(0) }
    recomposeCount++
    Text("Recompose count: $recomposeCount (should stay at 1)")
}

I expected one extra recomposition per character I typed into my text box, which would already have been a little bad, but instead I got a case of infinite, non-ending recompositions! This would have been invisible waste if I hadn't surfaced them via a text element:

https://github.com/JetBrains/compose-multiplatform/assets/43705986/f783ef92-bb29-458d-9656-5e5c60da947a

Once I added the @Immutable annotation to the empty RowScope interface (as the repro project suggests as a possible fix), the recompositions stopped.

This is clearly not intended behavior; Compose should not be getting confused about the immutability of an empty interface.

m-sasha commented 1 week ago

Does it behave differently on Android?