Travis Griggs
09/29/2023, 4:38 PMfun TopContainer(initial:Thing) {
val thing by remember { mutableStateOf(initial) }
Text(thing.description)
ThingEditor(thing, onChange = { newThing -> thing = newThing })
}
fun ThingEditor(thing:Thing, onChange: (Thing) -> Unit) {
Text("${thing.description.size}")
Button(onClick = { onChange(thing.modified) }) { Text("Modify") }
}
even though the remembered thing in the TopContainer will be updated, ThingEditor will not recompose. Fair enough. What's not clear is what the "normal" way to solve this is:
1. I can modify ThingEditor to enclose thing in a closure access. Which is OK, but just starts making closures every where if states being hoisted a number of levels up.
2. Replicate the remembered slot in ThingEditor. Initialize it with the value, update it locally (which will cause recomposition of the Editor to happen) and additionally, broadcast the change upwards by triggering the onChange (via a LaunchedEffect or some other flowy thing)
Which of these is the preferred pattern? Or is there a 3rd option. I just find myself frustrated when I'm coding along and things Just Work (I have lots of those with Compose which I'm thankful for) and then when it doesn't, I'm always flustered.Kevin Worth
09/29/2023, 4:53 PMThingEditor
not recompose? (why do you say “fair enough”?)Pablichjenkov
09/29/2023, 4:53 PMTravis Griggs
09/29/2023, 4:54 PM@Composable
fun TopContainer(initial: Offset) {
var thing: Offset by remember { mutableStateOf(initial) }
Column {
Text(thing.toString())
ThingEditor(thing, onChange = { newThing -> thing = newThing })
}
}
@Composable
fun ThingEditor(thing: Offset, onChange: (Offset) -> Unit) {
Column {
Text("${thing.theta}")
Button(onClick = { onChange(Offset(x = thing.y, y = thing.x)) }) { Text("Transpose") }
}
}
val Offset.theta: Float get() = (atan2(y, x))
@Preview(showBackground = true)
@Composable
private fun Preview() {
TopContainer(Offset(42f, 13f))
}
Pablichjenkov
09/29/2023, 5:19 PMKevin Worth
09/29/2023, 5:29 PMmyanmarking
10/02/2023, 10:36 AMKevin Worth
10/02/2023, 11:42 AMthing
didn’t cause ThingEditor
to recompose, then the library simply wouldn’t work. The parent TopContainer
says to ThingEditor
, “here is some state, make sure you recompose each time it changes”. On the other hand, the reason for using remember
is to say, “each time I (TopContainer
) recompose, I’m going to remember that I need to use the most recently changed version of `thing`” (with the very express purpose of making sure I don’t keep reusing initial
)“. That is, the remember
doesn’t say “remember to always use initial
“, it says “`remember` to use the latest value of thing
(and initially set its value to initial
)“.Travis Griggs
10/02/2023, 3:14 PMmyanmarking
10/02/2023, 3:19 PMTravis Griggs
10/02/2023, 3:23 PM@Composable
fun TopContainer(initial: Offset) {
var thing: Offset by remember { mutableStateOf(initial) }
Column {
Text(thing.toString())
ThingEditor(thing, onChange = { newThing -> thing = newThing })
}
}
@Composable
fun ThingEditor(thing: Offset, onChange: (Offset) -> Unit) {
val x by remember { mutableStateOf(thing.x) }
Column {
Text("${thing.theta}")
Slider(
value = x,
onValueChange = { x -> onChange(thing.copy(x = x)) },
valueRange = 0f..100f,
steps = 99
)
Button(onClick = { onChange(Offset(x = thing.y, y = x)) }) { Text("Transpose") }
}
}
val Offset.theta: Float get() = (atan2(y, x))
Zach Klippenstein (he/him) [MOD]
10/02/2023, 5:28 PMPablichjenkov
10/02/2023, 5:35 PMZach Klippenstein (he/him) [MOD]
10/02/2023, 5:42 PMPablichjenkov
10/02/2023, 5:58 PMZach Klippenstein (he/him) [MOD]
10/02/2023, 6:32 PMKevin Worth
10/02/2023, 8:41 PMderivedStateOf
, so are you clear on “remember with keys”?