Hoisting issue android Jetpack compose

110 Views Asked by At

I am new to Jetpack Compose and am having a problem with the hoisting topic. I have created a very basic app with a button, the app displays the amount of times you have clicked the button. I have tried to hoist the state from one composable to another. The second composable allows you to choose by how much should the increase be by each button click. I know it is possible to achieve everything in one composable but i have decided to hoist the state to the 2nd composable so could practice hoisting. Thanks

//Composable that the state has been hoisted to

@Composable
fun chooseYourIncrease(){

    var count by remember { mutableStateOf(0) }
    
    simpleCounter(countHold = {count + 2})


    
}

@Composable
fun simpleCounter (countHold:(Int)->Unit,
                   modifier: Modifier = Modifier
){
    
    Column(horizontalAlignment = Alignment.CenterHorizontally){
        Text("Please press button to increase value", fontSize = 20.sp)

        Spacer(modifier = Modifier.height(20.dp))

        Button(onClick = { countHold}) {
            Text(text = "Press to increase")

        }
        Spacer(modifier.height(20.dp))

        Text ("The new value is $countHold", fontSize = 20.sp)


    }

}

enter image description here

I get the following output on my screen

2

There are 2 best solutions below

2
On

Your code has several issues:

  • countHold lambda does nothing, it needs to actually change the count state
  • You need to pass count state and button logic separately
  • Button onClick handler doesn't need an Int, count state will be changed where it is hoisted
@Composable
fun ChooseYourIncrease() {
    var count by remember { mutableStateOf(0) }
    SimpleCounter(count = count, countHold = { count++ })    // 1
}

@Composable
fun SimpleCounter(
    count: Int,                                              // 2
    countHold: () -> Unit,
    modifier: Modifier = Modifier
) {
    Column(horizontalAlignment = Alignment.CenterHorizontally){
        Text("Please press button to increase value", fontSize = 20.sp)
        Spacer(modifier = Modifier.height(20.dp))
        Button(onClick = countHold) {                        // 3
            Text(text = "Press to increase")
        }
        Spacer(modifier.height(20.dp))
        Text("The new value is $count", fontSize = 20.sp)    // 4
    }
}
3
On

Please read about the State hoisting here. It makes the composable stateless by moving the state to a composable caller. In your case SimpleCounter() is the composable you want to make stateless and ChooseYourIncrease() is the composable caller. You are in the right direction but need a few modifications in your code:

  1. Add a value: Int param in SimpleCounter composable
  2. use the value in the text composable to print the count
  3. update the value of count in countHold callback
  4. Always use the CamelCase convention to define composable function names. (optional but preferred)
@Composable
fun ChooseYourIncrease(){

    var count by remember { mutableStateOf(0) }

    SimpleCounter(value = count, countHold = { count = count + 2})

}

@Composable
fun SimpleCounter (
    value: Int,
    countHold:() -> Unit,
    modifier: Modifier = Modifier
){

    Column(horizontalAlignment = Alignment.CenterHorizontally){
        Text("Please press button to increase value", fontSize = 20.sp)

        Spacer(modifier = Modifier.height(20.dp))

        Button(
            onClick = countHold
        ) {
            Text(text = "Press to increase")

        }
        Spacer(modifier.height(20.dp))

        Text ("The new value is $value", fontSize = 20.sp)


    }

}