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.
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
}
derivedStateOf
? 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.
Avoiding Unnecessary Recalculations
Cleaner and More Readable Code - Using derivedStateOf
allows you to express complex logic for derived state values in a more concise and readable way.
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.
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")
}
}
}
We have a simple counter state, count
, initialized with 0.
The derivedStateOf
creates a derived value derivedValue
, which is the double of count
.
When the "Increment Count" button is clicked, the count
state is incremented, and since derivedStateOf
is watching for changes to count
, it recalculates derivedValue
.
The UI displays both count
and derivedValue
, updating efficiently.
Notice that the derived value (count * 2
) is not recomputed unless the count
state changes.
derivedStateOf
?You should use derivedStateOf
in the following scenarios:
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.
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)
}
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)
}
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
}
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)
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.
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.
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:
Join our upcoming classes
https://www.androidengineers.in/courses