Tiger Oakes

mutableStateOf(list) vs mutableStateListOf()

The best way to work with lists and state in Jetpack Compose.

When working with lists in Jetpack Compose, you’ll end up seeing both mutableStateOf(listOf<T>()) and mutableStateListOf<T>(). They look pretty similar, but they have different purposes. Here’s a rundown on which one to use in what situation, as well what to do with other mutableState*Of functions.

Use mutableStateOf when working with immutable lists

State is designed to work with a single value. It only triggers recomposition if the value changes (if oldValue == newValue is false). If you pass in a list, it will only trigger recomposition if the list reference changes. If you’re working with a mutable list, the reference isn’t going to change so you won’t end up seeing your mutations reflected in the UI. Any changes to your list will need to be done by making a new copy.

val mutableList = remember { mutableListOf("A", "B", "C") }
val state = remember { mutableStateOf(mutableList) }
// This won't trigger recomposition
state.value.add("D")
// The value hasn't changed
state.value == mutableList // true

However, if you’re never changing the list yourself, this can be a good benefit. For example, if you’re working with a Room database, you don’t want to change a list of items returned from the database through mutation because the database itself won’t be changed. This is the same reason you would use List instead of MutableList - it makes it clear that the list should be treated as immutable.

Use mutableStateListOf when working with mutable lists

On the other hand, if you do want to mutate the list, you’ll want to have any mutations trigger recomposition. This is where mutableStateListOf comes in. It’s a MutableList that triggers recomposition when it’s mutated.

val state = remember { mutableStateListOf("A", "B", "C") }
// This will trigger recomposition
state.add("D")

You can think of it as a replacement for MutableList rather than a replacement for State or List. Reach for mutableStateListOf when you want to work with a mutable list (not a regular list) and have your changes reflected in the UI.

mutableStateMapOf follows the same pattern, but for maps

mutableStateMapOf is the same as mutableStateListOf, but for maps. It’s a MutableMap that triggers recomposition when it’s mutated.

If you need to be able to mutate your map inside of a composable, you’ll want to use mutableStateMapOf. Otherwise you’ll want to use a regular Map and mutableStateOf.

mutableDoubleStateOf, mutableFloatStateOf, mutableIntStateOf, and mutableLongStateOf are for primitive types

mutableDoubleStateOf, mutableFloatStateOf, mutableIntStateOf, and mutableLongStateOf are all equivalent to mutableStateOf, except they avoid autoboxing in JVM platforms (like Android). As a result, they’re more memory efficient and should be preferred when working with primitive types.