Is there downside replacing all remember(value) with remember { derivedStateOf { value } }?

Viewed 706

As in https://developer.android.com/jetpack/compose/side-effects, we have derivedStateOf which helps prevent unnecessary Recomposition.

With that, it makes me think, should we always use derivedStateOf instead of remember(value) as below?

// Instead of using
remember(value1) { ... }

// Use
remember { derivedStateOf {value1} }

Doing so will also ensure we don't recompose the function that contains the mutableState, but just all the composable functions using that mutableState.

Is there any downside of using derivedStateOf as opposed to remember(value)?

3 Answers

It is not recommended that you replace them all. If the object is re assigned, use remember. If the object content changes, use derivedstateof

If you replace them all with derivedStateOf, object changes will not be detected

remember is more flexible in some situations:

  1. You can have mutableState inside, which can be updated between reconfigurations and reset to the original value when value1 (or other keys) have changed.
  2. There may be a situation where you only need to update the value when some of the states used in the computation change, not any of them, in which case you can specify them in remember.

On the other hand, derivedStateOf also has its advantages:

  1. It doesn't cause recomposition unless the result of the computation has actually changed.
  2. It can be used outside the composite function, for example in a view model.

In general, if using derivedStateOf gives the expected behavior, you should prefer it over remember.

derivedStateOf is for observing a change or or a property change in State.

if value1 in both cases is a class that is not State derivedStateOf won't update

@Composable
private fun DerivedStateOfExample() {

    var numberOfItems by remember {
        mutableStateOf(0)
    }

    val count = numberOfItems

    val rememberedCount = remember(count) {
        count
    }

    val derivedCountWithoutState by remember {
        derivedStateOf {
            count
        }
    }

    val derivedCountWithState by remember {
        derivedStateOf {
            numberOfItems
        }
    }

    // Use derivedStateOf when a certain state is calculated or derived from other state objects.
    // Using this function guarantees that the calculation will only occur whenever one
    // of the states used in the calculation changes.
    val derivedStateMax by remember {
        derivedStateOf {
            numberOfItems > 5
        }
    }

    val newMax = remember(count > 5) {
        count
    }

    val derivedStateMin by remember {
        derivedStateOf {
            numberOfItems > 0
        }
    }

    Column(modifier = Modifier.padding(horizontal = 8.dp)) {

        Row(verticalAlignment = Alignment.CenterVertically) {
            Text(
                text = "Items: $numberOfItems\n" +
                        "derivedCountWithoutState: $derivedCountWithoutState\n" +
                        "derivedCountWithState: $derivedCountWithState\n" +
                        "newMax:$newMax\n" +
                        "rememberedCount:$rememberedCount, count: $count",
                modifier = Modifier.weight(1f)
            )
            IconButton(onClick = { numberOfItems++ }) {
                Icon(imageVector = Icons.Default.Add, contentDescription = "add")
            }
            Spacer(modifier = Modifier.width(4.dp))
            IconButton(onClick = { if (derivedStateMin) numberOfItems-- }) {
                Icon(imageVector = Icons.Default.Remove, contentDescription = "remove")
            }
        }


        if (derivedStateMax) {
            Text("Can't be more than 5 items", color = Color(0xffE53935))
        }
    }
}

enter image description here

derivedCountWithState won't update because it doesn't observe a state. Same goes for derivedStateMax when the value was not derived from numberOfItems but count > 5

Also newMax is updated when when remember(count > 5) turns from false to true. This is where derivedStateOf comes handy, you can check change in each update of State with a condition.

Related