https://kotlinlang.org logo
Title
m

myanmarking

01/12/2022, 5:46 PM
Having something like this:
fun someComposable(enabled: Boolean){
var valueField by remember{
mutableStateOf(..)
}
val errorInternal: Boolean = remember(enabled, valueField) {
derivedStateOf(valueField && enabled)
}
}
I need a state that depends on another state and a variable. derivedStateOf is for state only. This works but is this the correct approach?
c

Casey Brooks

01/12/2022, 5:48 PM
maybe wrap that other variable in
rememberUpdatedState()
? Putting
derivedStateOf
in a
remember { }
block seems wrong to me, though I can't really articulate why...
m

myanmarking

01/12/2022, 5:53 PM
Like this:
fun someComposable(enabled: Boolean){
var valueField by remember{
mutableStateOf(..)
}
val _enabled = rememberUpdatedState(enabled)
val errorInternal by derivedStateOf(valueField && enabled)}
}
c

Casey Brooks

01/12/2022, 5:59 PM
Yeah, I think that would work. Alternatively, since the value you're calculating for
errorInternal
is fast, you probably don't need to do that at all.
derivedStateOf
is more of a cache for expensive operations that depend on state values, rather than a requirement for computations based on state values. there's nothing wrong with computing simple values directly within the composable function
m

myanmarking

01/12/2022, 6:03 PM
ya but that value is used in the setup of another composable. Would that cause that composable to recompose ?
c

Casey Brooks

01/12/2022, 6:07 PM
Yes, it should, Compose is smart about that. It's more that the State variables tell Compose when to recompose, but it still checks each @Composable function individually based on the current values (whether State or not) to know what to recompose
m

myanmarking

01/12/2022, 6:10 PM
that’s one of the biggest confusions for me. There are cases i’m in doubt whether to use a state or a simple variable
c

Casey Brooks

01/12/2022, 6:13 PM
I'd suggest starting with the assumption you want normal variables for everything, keep writing the same type of code you'd write elsewhere in the non-Compose world. You shouldn't need to drop down to Compose/State-specific APIs unless you actually find that to be causing issues (things not recomposing when you expect, performance concerns, etc.).
a

Alex Vanyo

01/12/2022, 6:22 PM
I would alway start with the simplest code by just computing the value directly:
fun someComposable(enabled: Boolean){
	var valueField by remember {
		mutableStateOf(...)
	}
	val errorInternal = valueField && enabled
}
Casey is exactly right that
derivedStateOf
is a caching mechanism. It has its uses for fine-tuning when things recompose, but you shouldn’t really need to do that tuning unless you have a noticeable performance reason to do so. Just like any other caching mechanisms, you have to be more careful to invalidate the cache at the right time to see a tangible benefit without having subtle state issues
z

Zach Klippenstein (he/him) [MOD]

01/12/2022, 10:30 PM
And if you do end up using
derivedStateOf
from a composition directly, you definitely need to put it in a
remember
otherwise you’re re-creating the state every time, just like if you use
mutableStateOf
without a
remember
.
☝️ 1
l

lhwdev

01/13/2022, 5:00 AM
Note that
derivedStateOf
itself seems to be quite heavy to me. Also derivedStateOf can be used outside Compose. Thinking if something can be used outside Compose is also a great criteria like:
class Model {
    val a by mutableStateOf { 1 }
    val b by derivedStateOf { a - 3 }
}
States (and snapshot-related apis) are not that compose-specific. In fact I use them to manage states out of Compose.