Jonny
02/13/2023, 7:03 PMval currentFillPercent by rememberUpdatedState(fillPercent)
val currentIndicatorCount by rememberUpdatedState(indicatorCount)
val filledIndicatorCount by remember {
derivedStateOf {
((currentIndicatorCount * currentFillPercent / 100f) + 0.5f).toInt()
}
}
val fillColor by remember {
derivedStateOf {
when (currentFillPercent) {
in 0 until mediumThresholdPercentage -> colors.lowColor
in mediumThresholdPercentage until highThresholdPercentage -> colors.mediumColor
else -> colors.highColor
}
}
}
Alex Vanyo
02/13/2023, 7:16 PMremember
has no keys, the code inside will only be run once, and therefore it captures a reference to the initial value of the parameter. If the function recomposes, and there is a new value of the parameter, it won’t capture the new value.Alex Vanyo
02/13/2023, 7:18 PM@Composable
fun Repro(
fillPercent: Float,
indicatorCount: Int,
) {
val filledIndicatorCount by remember {
derivedStateOf {
((indicatorCount * fillPercent / 100f) + 0.5f).toInt()
}
}
}
then that’s equivalent to
@Composable
fun Repro(
fillPercent: Float,
indicatorCount: Int,
) {
val filledIndicatorCount by remember {
val calculation = {
((indicatorCount * fillPercent / 100f) + 0.5f).toInt()
}
derivedStateOf(calculation)
}
}
It’s a bit more clear that calculation
will be initialized once, and it will capture the initial fillPercent
and indicatorCount
valuesAlex Vanyo
02/13/2023, 7:20 PMrememberUpdatedState
fixes that by creating a state object that’s captured, instead of the value itself.
The by
delegate hides what’s going on a bit, so it looks almost the same:
val currentFillPercent by rememberUpdatedState(fillPercent)
val currentIndicatorCount by rememberUpdatedState(indicatorCount)
val filledIndicatorCount by remember {
derivedStateOf {
((currentIndicatorCount * currentFillPercent / 100f) + 0.5f).toInt()
}
}
is equivalent to
val currentFillPercentState = rememberUpdatedState(fillPercent)
val currentIndicatorCountState = rememberUpdatedState(indicatorCount)
val filledIndicatorCount by remember {
derivedStateOf {
((currentIndicatorCountState.value * currentFillPercentState.value / 100f) + 0.5f).toInt()
}
}
Jonny
02/13/2023, 7:26 PMAlex Vanyo
02/13/2023, 7:31 PMremember
or the remember
has a key with the parameter.
So an alternate solution would be add the parameters to the keys of `remember`:
@Composable
fun Repro(
fillPercent: Float,
indicatorCount: Int,
) {
val filledIndicatorCount by remember(indicatorCount, fillPercent) {
derivedStateOf {
((indicatorCount * fillPercent / 100f) + 0.5f).toInt()
}
}
}
But then at that point, derivedStateOf
is basically doing nothing since it is being recreated every time. So you might as well do
val filledIndicatorCount = remember(indicatorCount, fillPercent) {
((indicatorCount * fillPercent / 100f) + 0.5f).toInt()
}
But then there, you could also just remove the remember
and just inline the value calculation:
val filledIndicatorCount = ((indicatorCount * fillPercent / 100f) + 0.5f).toInt()
Jonny
02/13/2023, 7:33 PMJonny
02/13/2023, 7:38 PMAlex Vanyo
02/13/2023, 7:45 PMderivedStateOf
is a way to tweak how often and when work is done, which can be really useful in areas that are performance sensitive, especially if there are some inputs that change really often, but may not always change the output.
But you don’t have to use it for every piece of state that’s changingJonny
02/13/2023, 7:50 PM