aster.cloud aster.cloud
  • /
  • Platforms
    • Public Cloud
    • On-Premise
    • Hybrid Cloud
    • Data
  • Architecture
    • Design
    • Solutions
    • Enterprise
  • Engineering
    • Automation
    • Software Engineering
    • Project Management
    • DevOps
  • Programming
  • Tools
  • About
aster.cloud aster.cloud
  • /
  • Platforms
    • Public Cloud
    • On-Premise
    • Hybrid Cloud
    • Data
  • Architecture
    • Design
    • Solutions
    • Enterprise
  • Engineering
    • Automation
    • Software Engineering
    • Project Management
    • DevOps
  • Programming
  • Tools
  • About
  • Programming

Jetpack Compose — When Should I Use DerivedStateOf?

  • relay
  • December 1, 2022
  • 5 minute read

derivedStateOf — a really common question we see is where and when is the correct place to use this API?

The answer to this question is <strong class="ki jk">derivedStateOf {}</strong> should be used when your state or key is changing more than you want to update your UI. Or in other words, derivedStateOf is like distinctUntilChanged from Kotlin Flows or other similar reactive frameworks. Remember that Composables recompose when the Compose state object they read, changes. derivedStateOf allows you to create a new state object that changes only as much as you need.

Let’s take a look at an example. Here we have a username field and a button that enables when the username is valid.

/* Copyright 2022 Google LLC.
SPDX-License-Identifier: Apache-2.0 */

var username by remember { mutableStateOf("") }
val submitEnabled = isUsernameValid(username)
Initial state of username and submitEnabled

It starts off empty and so our state is false. Now when the user starts typing, our state correctly updates and our button becomes enabled.

But here is the problem, as our user keeps typing we are sending state to our button over and over again needlessly.

State updates after the user continues typing

This is where derivedStateOf comes in. Our state is changing more than we need our UI to update and so derivedStateOf can be used for this to reduce the number of recompositions.

/* Copyright 2022 Google LLC.
SPDX-License-Identifier: Apache-2.0 */

var username by remember { mutableStateOf("") }
val submitEnabled = remember {
  derivedStateOf { isUsernameValid(username) }
}
Updating the code to use derivedStateOf

Let’s go through the same example again to see the difference.

State updates with derivedStateOf

The user starts typing, but this time our username state is the only one that changes. The submit state just remains true. And of course, if our username becomes invalid. Our derived state correctly updates again.

Now, this example is a bit oversimplified. In a real app, Compose would most likely skip recomposition of the submit composable as its input parameters have not changed.

Read More  Google I/O 2019 | Pragmatic State Management in Flutter

The reality is, the situations when you need derivedStateOf can feel few and far between. But when you do find a case, it can be supremely effective at minimizing recomposition.

Always remember that there needs to be a difference in the amount of change between the input arguments and output result for <strong class="ki jk">derivedStateOf</strong> to make sense.

Some examples of when it could be used (not exhaustive):

  • Observing if scrolling passes a threshold (scrollPosition > 0)
  • Items in a list is greater than a threshold (items > 0)
  • Form validation as above (username.isValid())

FAQs

Now, let’s look at some other commonly asked questions about derivedStateOf.

Does derivedStateOf have to be remembered?

If it is inside a Composable function, yes. derivedStateOf is just like <a class="au li" href="https://developer.android.com/reference/kotlin/androidx/compose/runtime/package-summary#mutableStateOf(kotlin.Any,androidx.compose.runtime.SnapshotMutationPolicy)" target="_blank" rel="noopener ugc nofollow">mutableStateOf</a> or any other object that needs to survive recomposition. If you use it inside a composable function then it should be wrapped in a <a class="au li" href="https://developer.android.com/reference/kotlin/androidx/compose/runtime/package-summary#remember(kotlin.Any,kotlin.Any,kotlin.Any,kotlin.Function0)" target="_blank" rel="noopener ugc nofollow">remember</a> or else it will be reallocated on every recomposition.

/* Copyright 2022 Google LLC.
SPDX-License-Identifier: Apache-2.0 */

@Composable
fun MyComp() {
  // We need to use remember here to survive recomposition
  val state = remember { derivedStateOf { … } }
}

class MyViewModel: ViewModel() {
  // We don't need remember here (nor could we use it) because the ViewModel is
  // outside of Composition.
  val state = derivedStateOf { … }
}

What’s the difference between remember(key) and derivedStateOf?

Remember with keys of each state and derivedStateOf can seem quite similar at first glance.

/* Copyright 2022 Google LLC.
SPDX-License-Identifier: Apache-2.0 */

val result = remember(state1, state2) { calculation(state1, state2) }
val result = remember { derivedStateOf { calculation(state1, state2) } }

The difference between remember(key) and derivedStateOf is in the amount of recomposition. <strong class="ki jk">derivedStateOf {}</strong> is used when your state or key is changing more than you want to update your UI.

Read More  Just Your Type: Variable Fonts In Compose

Take for example enabling a button only if the user has scrolled a LazyColumn.

val isEnabled = lazyListState.firstVisibileItemIndex > 0

firstVisibleItemIndex will change 0, 1, 2 etc as the user scrolls and causes readers to recompose every time it changes. We only care about if it’s greater than 0 or not. There is a difference in the amount of input we have and output we need and so derivedStateOf is used here to buffer out that unnecessary recomposition.

val isEnabled = remember {
derivedStateOf { lazyListState.firstVisibleItemIndex > 0 }
}

Now, let’s say we have an expensive function that calculates something for us with a parameter. We want our UI to recompose any time the output of that function changes (importantly, the function is also idempotent). We use remember with a key here, as our UI needs to update just as much as our key changes. That is, we have the same amount of input and output.

val output = remember(input) { expensiveCalculation(input) }

Do I ever need to use remember(key) and derivedStateOf together? When is this needed?

This is where things get a little tricky. derivedStateOf can only update when it reads a Compose state object. Any other variables read inside derivedStateOf will capture the initial value of that variable when the derived state is created. If you need to use those variables in your calculation, then you can provide them as a key to your remember function. This concept is much easier to understand with an example. Let’s take our isEnabled example from before and expand it to also have a threshold for when to enable the button, rather than 0.

Read More  How To: Install Python 2.7 In Ubuntu
/* Copyright 2022 Google LLC.
SPDX-License-Identifier: Apache-2.0 */

@Composable
fun ScrollToTopButton(lazyListState: LazyListState, threshold: Int) {
  // There is a bug here
  val isEnabled by remember {
    derivedStateOf { lazyListState.firstVisibleItemIndex > threshold }
  }
  
  Button(onClick = { }, enabled = isEnabled) {
    Text("Scroll to top")
  }
}

Here we have a button that enables when a list is scrolled over a threshold. We are correctly using derivedStateOf to remove the extra recomposition, but there is a subtle bug. If the threshold parameter changes, our derivedStateOf won’t take the new value into account as it captures the initial value on creation for any variable that isn’t a compose state object. As threshold is an Int, whatever is the first value that is passed into our composable will be captured and used for the calculation from then on. ScrollToTopButton will still recompose, as its inputs have changed, but as remember without any keys caches across recomposition, it will not reinitialise the derivedStateOf with the new value.

We can see this by looking at the outputs from our code. At first everything is working correctly.

But then a new value (5) for threshold is passed into our composable.

Even though our scrollPosition is less than threshold, isEnabled is still set to true.

The fix here is to add threshold as a key for remember, this will reinitialise our derivedStateOf state anytime threshold changes.

/* Copyright 2022 Google LLC.
SPDX-License-Identifier: Apache-2.0 */

val isEnabled by remember(threshold) {
  derivedStateOf { lazyListState.firstVisibleItemIndex > threshold }
}

Now we can see, when the threshold changes, the isEnabled state correctly updates.

Do I need to use derivedStateOf to combine multiple states together?

Most likely, no. If you have multiple states that are combining together to create a result then you probably want recomposition to happen any time one of them changes.

Take for example a form that takes in a first name and last name and displays a full name.

/* Copyright 2022 Google LLC.
SPDX-License-Identifier: Apache-2.0 */

var firstName by remember { mutableStateOf("") }
var lastName by remember { mutableStateOf("") }

val fullName = "$firstName $lastName"

Here, as our output changes just as much as our input, derivedStateOf is not doing anything and is just causing a small overhead. derivedStateOf also isn’t helping with asynchronous updates, the Compose state snapshot system is dealing with that separately and these calls here are synchronous.

In this case, there is no need for an extra derived state object at all.

/* Copyright 2022 Google LLC.
SPDX-License-Identifier: Apache-2.0 */

var firstName by remember { mutableStateOf("") }
var lastName by remember { mutableStateOf("") }

val fullName = "$firstName $lastName"

Conclusion

To sum up, remember that derivedStateOf is used when your state or key is changing more than you want to update your UI. If you don’t have a difference in the amount of input compared with output, you don’t need to use it.

By Ben Trengrove
Source Android

relay

Related Topics
  • Android
  • API
  • derivedStateOf
  • Jetpack Compose
You May Also Like
View Post
  • Automation
  • Programming

Learn Expect By Writing And Automating A Simple Game

  • March 14, 2023
SQL
View Post
  • Data
  • Programming

Infrastructure from Code: the New Wave of Cloud Infrastructure Management

  • February 16, 2023
View Post
  • Programming

Go 1.20 Is Released!

  • February 13, 2023
View Post
  • Computing
  • Programming

Tiny Snippets Of Code That Changed The World

  • January 23, 2023
View Post
  • Computing
  • Programming

How To Migrate Your Code From PHP 7.4 to 8.1

  • December 26, 2022
View Post
  • Programming
  • Software Engineering

10 Tips For Writing Clean Code

  • December 15, 2022
View Post
  • Programming
  • Software
  • Technology

Compose For Wear OS 1.1 Is Now Stable: Check Out New Features!

  • December 12, 2022
View Post
  • Architecture
  • Programming

Introducing The Architecture Templates

  • December 12, 2022

Stay Connected!
LATEST
  • 1
    My First Pull Request At Age 14
    • March 24, 2023
  • 2
    AWS Chatbot Now Integrated Into Microsoft Teams
    • March 24, 2023
  • 3
    Verify POST Endpoint Availability With Uptime Checks
    • March 24, 2023
  • 4
    Sovereign Clouds Are Becoming A Big Deal Again
    • March 23, 2023
  • 5
    Ditching Google: The 3 Search Engines That Use AI To Give Results That Are Meaningful
    • March 23, 2023
  • 6
    Pythonic Techniques For Handling Sequences
    • March 21, 2023
  • 7
    Oracle Cloud Infrastructure to Increase the Reliability, Efficiency, and Simplicity of Large-Scale Kubernetes Environments at Reduced Costs
    • March 20, 2023
  • 8
    Monitor Kubernetes Cloud Costs With Open Source Tools
    • March 20, 2023
  • 9
    What Is An Edge-Native Application?
    • March 20, 2023
  • 10
    Eclipse Java Downloads Skyrocket
    • March 19, 2023
about
Hello World!

We are aster.cloud. We’re created by programmers for programmers.

Our site aims to provide guides, programming tips, reviews, and interesting materials for tech people and those who want to learn in general.

We would like to hear from you.

If you have any feedback, enquiries, or sponsorship request, kindly reach out to us at:

[email protected]
Most Popular
  • 1
    Cloudflare Takes On Online Fraud Detection Market
    • March 15, 2023
  • 2
    Linux Foundation Training & Certification & Cloud Native Computing Foundation Partner With Corise To Prepare 50,000 Professionals For The Certified Kubernetes Administrator Exam
    • March 16, 2023
  • 3
    Cloudflare Democratizes Post-Quantum Cryptography By Delivering It For Free, By Default
    • March 16, 2023
  • 4
    Daily QR “Scan Scams” Phishing Users On Their Mobile Devices
    • March 16, 2023
  • 5
    Lockheed Martin Launches Commercial Ground Control Software For Satellite Constellations
    • March 14, 2023
  • /
  • Platforms
  • Architecture
  • Engineering
  • Programming
  • Tools
  • About

Input your search keywords and press Enter.