SearchBar: adopt outside text changes in a side effect

SearchBar keeps a TextFieldValue so that the cursor ends up behind text that was
changed from the outside (a search started by typing on a physical keyboard, or
a reset search). That value was updated during composition, which is an
anti-pattern: the value read earlier in the same composition is what gets drawn,
so the write only schedules another recomposition pass of the search bar - and
it can be dropped entirely if the composition does not complete.

Do the same update in a SideEffect, after the composition. No behaviour change
for the user.
This commit is contained in:
2026-09-10 20:41:01 +02:00
parent 73c3683740
commit 79f229de6d

View File

@@ -24,6 +24,7 @@ import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.SideEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
@@ -143,8 +144,14 @@ fun SearchBar(
val textFieldValue = remember {
mutableStateOf(TextFieldValue(value, TextRange(value.length)))
}
if (textFieldValue.value.text != value) {
textFieldValue.value = TextFieldValue(value, TextRange(value.length))
// Characters the user typed are already in this value; onValueChange below keeps the cursor
// where the user put it. Text that changed from the outside - the search was reset, or a
// character was inserted by the physical keyboard handler - is adopted here, with the cursor at
// the end. This must not write state during composition, so it runs in a side effect after it.
SideEffect {
if (textFieldValue.value.text != value) {
textFieldValue.value = TextFieldValue(value, TextRange(value.length))
}
}
LauncherCard(