State Hoisting & UDF - devrath/ComposeAlchemy GitHub Wiki

π™²π™Ύπ™½πšƒπ™΄π™½πšƒπš‚
Stateful & Stateless Composables
Why prefer Stateless Composables
Example for Stateless Composable to handle action and display the state

Stateful & Stateless Composables

Stateful Composable

  • It is a composable that contains a state.
  • Even if a reference in the composable changes the state or modifies the appearance if that state is not maintained within the confined boundaries of the composable, it is not stateful composable.
  • The only advantage of a stateful composable is that we need to use a composable that comes with all the functionalities of the composable functionality.
  • But we should always try to avoid the stateful composable.

Stateless Composable

  • If the composable does not contain the state within the confined boundaries of the composable, Then it is called stateless composable.

Why prefer Stateless Composables

  • We should not completely go for stateless but we need to pass the state into the composable from outside so that the state is not completely managed inside of the composable.
  • Say we have a counter composable that encloses the state of the counter within the composable.
  • Now say we use the counter composable in our screen and extend its functionality by resetting the composable.
  • This is 🚫 not possible because since we cannot access the state of the composable outside the composable, There is no way to reset it.
  • Solution: We need to lift the state outside the composable and alter it outside if needed and when required by passing the state to it.
  • This provides better usability of the composables.

Example for Stateless Composable to handle action and display the state

  • See how the state is hoisted at the parent.
  • Also how the action is delegated to parent and handled at the parent level

code

@Composable
fun CounterDemoScreen(modifier: Modifier = Modifier) {

    var counterState by remember { mutableIntStateOf(0) }

    Scaffold(
        modifier = Modifier.fillMaxSize()
    ) { padding ->
        Box(
            modifier = Modifier
                .fillMaxSize()
                .padding(padding),
            contentAlignment = Alignment.Center
        ) {
            Column(
                modifier = Modifier.fillMaxSize(),
                horizontalAlignment = Alignment.CenterHorizontally,
                verticalArrangement = Arrangement.Center
            ) {
                CounterWidget(
                    modifier = Modifier.fillMaxWidth(),
                    counter = counterState,
                    updateCount = {
                        counterState++
                    }
                )
                Button(
                    modifier = Modifier.wrapContentSize(),
                    onClick = {
                        counterState = 0
                    }
                ) {
                    Text(text = "Reset")
                }
            }

        }
    }

}

@Composable
fun CounterWidget(
    modifier: Modifier = Modifier,
    counter: Int,
    updateCount: (Int)-> Unit
){
    Box(
        modifier = modifier
            .wrapContentSize()
    ) {
        Column {
            Text(text = "Current Value -> $counter")
            Button(
                onClick = {
                    updateCount(counter)
                }
            ) {
                Text(text = "Click to Increment")
            }
        }
    }
}
⚠️ **GitHub.com Fallback** ⚠️