How to hoist multiple states?

Viewed 268

When we are talking about Compose we will definitely face the approach of state hoisting. Which is pretty comfortable and doesn't requires rocket science knowledge. But here comes into play bunch of other questions and another bunch of possible solutions. That's all about numerous parameters passing through the fun declaration. Going back to the old good days we could allow ourselves to have a container which will hold mostly all of the params(simple one). On the other hand we can have default parameters, but in any case that doesn't help to deal with multiple(huge number) lines of function declaration. Any thoughts here?

If we dive a bit deeper and review the androidx.compose.***(material i.e.) package we'll find a lot of composables that actually are having many params(lambdas) for state hoisting. So I believe that is a common approach. We can take the TextField composable, which is a nice example of what I'm saying:

@Composable
fun TextField(
    value: String,
    onValueChange: (String) -> Unit,
    modifier: Modifier = Modifier,
    textStyle: TextStyle = AmbientTextStyle.current,
    label: @Composable (() -> Unit)? = null,
    placeholder: @Composable (() -> Unit)? = null,
    leadingIcon: @Composable (() -> Unit)? = null,
    trailingIcon: @Composable (() -> Unit)? = null,
    isErrorValue: Boolean = false,
    visualTransformation: VisualTransformation = VisualTransformation.None,
    keyboardType: KeyboardType = KeyboardType.Text,
    imeAction: ImeAction = ImeAction.Unspecified,
    onImeActionPerformed: (ImeAction, SoftwareKeyboardController?) -> Unit = { _, _ -> },
    onTextInputStarted: (SoftwareKeyboardController) -> Unit = {},
    interactionState: InteractionState = remember { InteractionState() },
    activeColor: Color = MaterialTheme.colors.primary,
    inactiveColor: Color = MaterialTheme.colors.onSurface,
    errorColor: Color = MaterialTheme.colors.error,
    backgroundColor: Color = MaterialTheme.colors.onSurface.copy(alpha = ContainerAlpha),
    shape: Shape =
        MaterialTheme.shapes.small.copy(bottomLeft = ZeroCornerSize, bottomRight = ZeroCornerSize)
)

Sure, it also contains a lot of configuration params and composable slots. Still, the question remains. I have few options when such situation could happen:

  • A complex UI composable with a lot of possible user Events, i.e. TextField
  • A complex UI structure/hierarchy with multiple composables that wrap each other and need to hoist events/user inputs from bottom to the top. Well, hoisting could increase the level of parameters(lambdas) through each level.
  • Your case here

P.S. I'm not saying that it is wrong or there is something bad about it, just trying to find a comfortable way.

P.P.S. I know it is all about having trade-offs.

1 Answers

Personally I think structuring the parameters into data classes could give a bit more readability, for bot the consumer and provider.

For ex: activeColor, inactiveColor, errorColor, backgroundColor. Could be moved into a

data class TextFieldColors(
    val activeColor: Color, 
    val inactiveColor: Color, 
    val errorColor: Color, 
    val backgroundColor: Color)

(Pardon the naming here)

You could do this similarly for icons, placeholders and basically structure your parameters in a way that makes sense both for the provider & consumer.

Additionally I believe reusing these already created Parameter classes can help when extending existing components.

Related