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 |
- 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.
- If the composable does not contain the state within the confined boundaries of the composable, Then it is called stateless composable.
- 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.
- 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")
}
}
}
}