derivedStateOf in Jetpack Compose

One of the important tools in the Compose state management toolbox is the derivedStateOf function. This function allows developers to efficiently derive state values from other states, ensuring that UI updates only occur when necessary.

In this blog, we'll dive deep into what derivedStateOf is, why you should use it, how it works, and when to use it with detailed code examples.

What is derivedStateOf?

It lets you calculate a state that is based on other states and only recomputes when the underlying states change.

A derived state is a state value that depends on one or more other states. However, it’s not directly updated by UI elements, and instead, it is recalculated automatically when any of the underlying states change. This helps you avoid unnecessary recomputations and optimizations for specific UI elements.

In simpler terms, derivedStateOf is like a cached computation that only recalculates when the dependent states change, improving performance.

val derivedValue = derivedStateOf { 
    someState * 2 
}

Why Use derivedStateOf?

  1. Performance Optimization - Without derivedStateOf, you might end up recalculating or re-rendering UI elements unnecessarily when the underlying state doesn’t actually change in a meaningful way.

  2. Avoiding Unnecessary Recalculations

  3. Cleaner and More Readable Code - Using derivedStateOf allows you to express complex logic for derived state values in a more concise and readable way.

How Does derivedStateOf Work?

The derivedStateOf function takes a lambda block that computes the derived value, and it will only recompute the value when the state used inside the lambda changes.

Here’s the basic syntax:

val derivedValue = derivedStateOf { 
    // Your computation based on other state values
    someState * 2 
}

In this case, the value of derivedValue will be recalculated whenever someState changes.

Example: Basic Usage of derivedStateOf

Let’s walk through a simple example to understand how derivedStateOf works:

import androidx.compose.runtime.*

@Composable
fun DerivedStateExample() {
    var count by remember { mutableStateOf(0) }
    
    // Create a derived state
    val derivedValue = derivedStateOf { 
        count * 2 // Derived value is count * 2
    }
    
    Column {
        Text("Count: $count")
        Text("Derived Value: ${derivedValue.value}")
        
        Button(onClick = { count++ }) {
            Text("Increment Count")
        }
    }
}

Explanation of the Example:

  1. We have a simple counter state, count, initialized with 0.

  2. The derivedStateOf creates a derived value derivedValue, which is the double of count.

  3. When the "Increment Count" button is clicked, the count state is incremented, and since derivedStateOf is watching for changes to count, it recalculates derivedValue.

  4. The UI displays both count and derivedValue, updating efficiently.

Notice that the derived value (count * 2) is not recomputed unless the count state changes.

When to Use derivedStateOf?

You should use derivedStateOf in the following scenarios:

1. When You Need to Compute a Value Based on One or More States

If you need to calculate a value that depends on one or more other states, you can use derivedStateOf to store that value. This ensures that the value is recalculated only when the relevant states change.

For example, if you need a derived state representing a value based on multiple inputs, such as the result of a calculation, derivedStateOf can be used to simplify the logic.

2. When the Computation Is Expensive

If the calculation or logic to derive the value is computationally expensive, using derivedStateOf will avoid redundant calculations and optimize your UI performance.

For example, you can derive a value by combining multiple expensive computations but only recalculate when the dependent states change.

val result = derivedStateOf {
    computeExpensiveValue(state1, state2)
}

3. When You Want to Cache Derived Values

If you want to cache a computed value and avoid recalculating it unnecessarily on every recomposition, derivedStateOf will handle that efficiently.

val cachedValue = derivedStateOf {
    expensiveComputation(state1)
}

4. When You Need to Optimize UI Recomposition

By ensuring that derived values are only recalculated when necessary, you can optimize the recomposition behavior of your composables. It helps to prevent redundant state changes from triggering UI updates for the entire component tree.

For instance, in a list, if you want to calculate the sum of items based on a state list, derivedStateOf ensures the calculation happens only when the list changes.

val sum = derivedStateOf { 
    list.sum() // This computation only occurs when `list` changes
}

Advanced Example:

Let's combine a list and a derived state to show how derivedStateOf can optimize performance in a more complex UI.

@Composable
fun ShoppingCart() {
    val items = remember { mutableStateListOf<Item>() }
    val totalPrice = remember { mutableStateOf(0f) }

    // Derived state to calculate the total price
    val derivedTotalPrice = derivedStateOf {
        items.sumOf { it.price } // Only recalculates when `items` changes
    }

    Column {
        LazyColumn {
            items(items) { item ->
                Text(text = "${item.name} - $${item.price}")
            }
        }
        Spacer(modifier = Modifier.height(20.dp))
        Text(text = "Total Price: $${derivedTotalPrice.value}")
        Button(onClick = { items.add(Item("Item ${items.size + 1}", 10f)) }) {
            Text("Add Item")
        }
    }
}

data class Item(val name: String, val price: Float)

Explanation of the Example:

  • The derivedStateOf calculates the derivedTotalPrice based on the items list.

  • The derivedTotalPrice only updates when the items list changes, which prevents unnecessary recomputation.

  • As items are added to the cart, the total price updates efficiently, without recomputing the value on every recomposition.

Here’s a breakdown of how derivedStateOf works under the hood:

  • Tracking Dependencies: Compose watches the states that a derivedStateOf depends on (like a variable or state). It only recalculates the derived value when one of those states changes.

  • Caching the Value: When you first calculate a derived state, Compose stores the result. It won't recalculate it until the underlying state changes.

  • Efficient Updates: When the dependent state changes, Compose recalculates the derived value and updates only the parts of the UI that depend on it. Other parts of the UI stay the same.

This means derivedStateOf helps avoid unnecessary calculations and makes your app faster by only updating what's needed when something changes.

val count = remember { mutableStateOf(0) }
val doubledCount = derivedStateOf { count.value * 2 }

When count changes, doubledCount is recalculated, but only when it's actually used.

Conclusion

In Jetpack Compose, derivedStateOf is a powerful tool for optimizing the performance and readability of your UI. By allowing you to create derived states that only recompute when necessary, it ensures that your app remains responsive and efficient.

  • Use derivedStateOf when you need to compute a value based on other state values.

  • It helps optimize performance by caching values and avoiding unnecessary recomputations.

  • Use it to reduce UI recomposition, making your app more efficient.

By applying derivedStateOf in the right scenarios, you can ensure that your Compose-based Android apps remain performant and scalable.

Akshay Nandwana
Founder AndroidEngineers

You can connect with me on:


Book 1:1 Session here
Click Here

Join our upcoming classes
https://www.androidengineers.in/courses

Love from our past students

Excellent list of questions really helped me to coverup all the topics before interview.

Saiteja Janjirala

10th Oct, 2024

I had an exceptional experience with the 1:1 mentorship session. Akshay was incredibly friendly and provided invaluable guidance on focusing on long-term goals. They also gave great interview tips, including a thorough resume review. Additionally, the discussion on Data Structures and Algorithms (DSA) was insightful and practical. Highly recommended for anyone looking to advance their career!

Nayab khan

11th Sep, 2024

Cleared my major points for what I am missing in the resume and also suggested what I can work on for further growth in the career.

Ketan Chaurasiya

7th Aug, 2024

What impressed me most was his personalized approach and practical tips that I could immediately apply. Akshay’s guidance not only improved my technical skills but also boosted my confidence in navigating my career path. His insights and encouragement have been a game-changer for me. I highly recommend Akshay’s mentorship to anyone looking to advance their Android development career.

Hardik Kubavat

5th Aug, 2024

2025© Made with   by Android Engineers.