Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why chained mutable state is not updated?

The value of diabledValue is never updated. It always has value "A" How to properly chain mutableStates?

@Composable
fun DropDownDemo() {
    var expanded by remember { mutableStateOf(false) }
    val items = listOf("A", "B", "C", "d", "E", "F")
    var selectedIndex by remember { mutableStateOf(0) }
    var disabledValue by remember { mutableStateOf(items[selectedIndex]) }
    Log.e("mcheck", "$selectedIndex $disabledValue")
    Box(
        modifier = Modifier
            .fillMaxSize()
            .wrapContentSize(Alignment.TopStart)
    )
    {
        Text(
            items[selectedIndex],
            modifier = Modifier
                .fillMaxWidth()
                .clickable(onClick = { expanded = true })
                .background(Color.Gray)
        )
        DropdownMenu(
            expanded = expanded,
            onDismissRequest = { expanded = false },
            modifier = Modifier
                .fillMaxWidth()
                .background(Color.Red)
        ) {
            items.forEachIndexed { index, s ->
                DropdownMenuItem(onClick = {
                    selectedIndex = index
                    expanded = false
                }) {
                    var disabledText = if (s == disabledValue) {
                        " Disabled"
                    } else {
                        ""
                    }
                    Text(text = s + disabledText)
                }
            }
        }
    }
}
like image 915
Yarh Avatar asked Mar 03 '26 21:03

Yarh


1 Answers

You actually don't need disabledValue to be State or remembered at all, so simply

val disabledValue = items[selectedIndex]

is the best thing you can do here. This is because getting item by index from array list is not expensive, and your composable has to recompose every time selectedIndex changes.

And to answer your question "How to properly chain mutableStates?" - if one of those wouldn't be the case, there is a derivedStateOf for such cases.

For example, if the calculation is somewhat expensive:

val list = ...
var selectedId by remember { mutableStateOf("...") }
val disabledValue by remember {
    derivedStateOf {
        list.find { it.id == selectedId }
    }
}

Here, searching in a list is quite expensive calculation. With derivedStateOf, it will be done only when selectedId is changed. When your composable is recomposed because of some other change, derivedStateOf will use cached value and saves you that calculation.

And in this example:

val listState = rememberLazyListState()
val toolbarElevation by remember {
    derivedStateOf {
        if (listState.firstVisibleItemIndex == 0) 0.dp else 8.dp
    }
}

TopAppBar(
    elevation = toolbarElevation
)

listState.firstVisibleItemIndex is changing quite often when you scroll, but your composable have to recompose only when it changes from 0 to 1 and vice versa, and that's what derivedStateOf does for you.

derivedStateOf would also work for your case, but like I said, it's not necessary.

like image 134
Jan Bína Avatar answered Mar 08 '26 23:03

Jan Bína



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!