Side Effect: derivedStateOf - devrath/ComposeAlchemy GitHub Wiki

When to use derivedStateOf

  • This state is used when we want to increase the performance of composables 🏃‍♀️ by updating the UI only when necessary which saves the number of re-composition counts.
  • Example only when a certain condition is met, we do the re-composition, Thus increasing the performance.

How normal state updation happens

  • Observe initially the first time the composable is composed all the composables are composed of column till the text composable
  • When we click the button and update the state by incrementing it, thus updating the mutableState, the Parent root is composed than the column composable is composed. Notice the Button & Text is not re-composed.

output

Composition occurs
Counter READ: false
Column is composed
Button is composed
Click invoked - New value of count = 1
Composition occurs
Counter READ: false
Column is composed
Click invoked - New value of count = 2
Composition occurs
Counter READ: false
Column is composed
Click invoked - New value of count = 3
Composition occurs
Counter READ: false
Column is composed
Click invoked - New value of count = 4
Composition occurs
Counter READ: true
Column is composed

code

@Composable
fun DerivedStateDemo() {

    Log.d("TypeDerivedState-Demo","Composition occurs")
    // We have a state defined in the composable
    var counter by remember { mutableIntStateOf(0) }
    Log.d("TypeDerivedState-Demo","Counter READ: ${counter>3}")

    Column(
        modifier = Modifier.fillMaxSize(),
        verticalArrangement = Arrangement.Center,
        horizontalAlignment = Alignment.CenterHorizontally
    ) {
        Log.d("TypeDerivedState-Demo", "Column is composed")
        Button(
            onClick = {
                counter += 1
                Log.d("TypeDerivedState-Demo", "Click invoked - New value of count = $counter")
            }
        ) {
            Log.d("TypeDerivedState-Demo", "Button is composed")
            Text(text = "CLICK")
        }
    }
}

How normal state updation happens

  • Now since I added the calculation as derived state
  • Only when the condition is satisfied only then the recomposition will happen from parent to where its been used

output

Composition occurs
Calculation Triggered
Counter READ: false
Column is composed
Button is composed
Click invoked - New value of count = 1
Click invoked - New value of count = 2
Click invoked - New value of count = 3
Click invoked - New value of count = 4
Composition occurs
Counter READ: true
Column is composed

code

@Composable
fun DerivedStateDemo() {

    Log.d("TypeDerivedState-Demo","Composition occurs")
    // We have a state defined in the composable
    var counter by remember { mutableIntStateOf(0) }
    // We now have a derived state
    val calculation by remember {
        Log.d("TypeDerivedState-Demo", "Calculation Triggered")
        derivedStateOf { counter > 3 }
    }

    Log.d("TypeDerivedState-Demo","Counter READ: $calculation")

    Column(
        modifier = Modifier.fillMaxSize(),
        verticalArrangement = Arrangement.Center,
        horizontalAlignment = Alignment.CenterHorizontally
    ) {
        Log.d("TypeDerivedState-Demo", "Column is composed")
        Button(
            onClick = {
                counter += 1
                Log.d("TypeDerivedState-Demo", "Click invoked - New value of count = $counter")
            }
        ) {
            Log.d("TypeDerivedState-Demo", "Button is composed")
            Text(text = "CLICK")
        }
    }
}