https://kotlinlang.org logo
Title
s

Stylianos Gakis

08/24/2021, 9:05 PM
Curious about when a composable function should return a
State<T>
or just
T
. An example from “Crane” the official android samples inside thread 🧵
One example function defined in the Crane app looks like this
@Composable
private fun tintPeopleUserInput(
    transitionState: MutableTransitionState<PeopleUserInputAnimationState>
): State<Color> {
    val validColor = MaterialTheme.colors.onSurface
    val invalidColor = MaterialTheme.colors.secondary

    val transition = updateTransition(transitionState)
    return transition.animateColor(
        transitionSpec = { tween(durationMillis = 300) }
    ) {
        if (it == Valid) validColor else invalidColor
    }
}
Now as I understand it, Compose is smart enough to just handle it perfectly fine if the function looked like this instead
@Composable
private fun tintPeopleUserInput(
    transitionState: MutableTransitionState<PeopleUserInputAnimationState>
): Color {
    val validColor = MaterialTheme.colors.onSurface
    val invalidColor = MaterialTheme.colors.secondary

    val transition = updateTransition(transitionState, label = "")
    val color by transition.animateColor(
        transitionSpec = { tween(durationMillis = 300) }, label = ""
    ) {
        if (it == Valid) validColor else invalidColor
    }
    return color
}
So why would one ever chose one over the other? If they are functionally equivalent, it feels like the simple non-state return type should be preferable? Are there any guidelines on this?
z

Zach Klippenstein (he/him) [MOD]

08/24/2021, 9:09 PM
Returning the raw value means it will cause the caller’s recompose scope to recompose on every animation frame, because the function itself reads the animation value. By returning a
State
, this function allows the caller to determine where to read the animated state, and thus how much/what to recompose/reexecute on each frame.
e.g. the caller might only read from the returned
State
inside a
drawBehind
call, which means that each animation frame of this transition would only trigger a new draw pass, not a whole recomposition.
c

corneil

08/24/2021, 9:09 PM
I think since the input the the function is derived from State the function is going to be invoked on a change and the rest of the related functions. 🤷‍♂️
s

Stylianos Gakis

08/24/2021, 9:14 PM
Right! I think I understand it, you have explained this here as well right? If the value is read directly on the top of the calling function, that entire composable will be re-composed whenever the color value changes. Am I getting this right?
z

Zach Klippenstein (he/him) [MOD]

08/24/2021, 9:15 PM
directly on the top of the calling function
I’m not sure what you mean by this, but I think you’ve probably got the right idea
Also note that it’s not necessarily bad to recompose the whole thing, and if that’s what you need to do, then it’s fine. But by returning a
State
, the function doesn’t force that to be the only option – it leaves it up to the caller
s

Stylianos Gakis

08/24/2021, 9:21 PM
I meant like if it’s read as the first line into the calling composable for example. Meaning in would be in the outer-most recompose scope, therefore everything under it would be re-composed. Like this does:
Column {
        val transitionState = remember { peopleState.animationState }
        val tint: Color = tintPeopleUserInput(transitionState) // here

        val people = peopleState.people
        CraneUserInput(
            text = ...,
            vectorImageId = ...,
            tint = tint,
            onClick = {}
        )
        if (transitionState.targetState == Invalid) {
            Text(...)
        }
    }
The whole CraneUserInput and whatever else was included inside this Column (and outside of it, since it’s inline) would recompose instead of only whatever uses tint inside the CraneUserInput. Would this be the case?
z

Zach Klippenstein (he/him) [MOD]

08/24/2021, 9:31 PM
yes, if
tintPeopleUserInput
returned just
T
instead of
State<T>
, correct
unless i’m misunderstanding, it doesn’t matter what line it’s on
s

Stylianos Gakis

08/24/2021, 9:33 PM
Amazing thank you for helping me out! And also I would like to say that your posts that I linked before have been invaluable to me, I would never be able to understand any of this without it. Thank you so much!
z

Zach Klippenstein (he/him) [MOD]

08/24/2021, 9:35 PM
glad they helped!