mutableStateOf: att skapa observerbart tillstånd och Compose-reaktivitet

Författare: IT Sectr Publicerad: 2026-06-28 Lästid: 7 min

mutableStateOf är en funktion i Jetpack Compose som skapar en behållare för föränderligt observerbart tillstånd. När värdet inuti denna behållare ändras startar Compose automatiskt omkomponering av alla komponenter som läser detta tillstånd. Utan mutableStateOf skulle UI inte kunna uppdateras reaktivt vid dataändringar. Enligt Google Android Developers, 2026 är mutableStateOf den primära byggstenen för lokalt tillstånd i Compose.

Huvudpunkter

  • mutableStateOf skapar en MutableState-behållare som övervakas av Compose Runtime
  • Omkomponering startas automatiskt när value för detta State-objekt ändras
  • Delegering via var gör det möjligt att använda mutableStateOf utan att anropa .value
  • Nycklar i remember(mutableStateOf) behövs inte — State meddelar själv Compose om ändringar
  • Snapshot-systemet garanterar läskonsistens i flertrådad miljö

Vad är mutableStateOf i Jetpack Compose

mutableStateOf är en funktion från paketet compose.runtime som skapar ett MutableState<T>-objekt som lagrar ett värde och kan meddela Compose Runtime om ändringar. Signatur: fun <T> mutableStateOf(value: T, policy: SnapshotMutationPolicy<T> = structuralEquality()): MutableState<T>. Parametern policy bestämmer när en ändring anses betydande — vid strukturell likhet, vid referensiell likhet eller aldrig.

MutableState är ett gränssnitt med en enda egenskap value: getter för läsning och setter för skrivning. När settern anropas registrerar Compose Runtime ändringen i en snapshot och markerar alla Composable-funktioner som läser denna State-variabel som omkomponeringskrävande. Denna process sker synkront inom en snapshot-cykel, vilket eliminerar mellanliggande tillstånd vid kaskadförändringar.

Parameter policy — det andra argumentet till mutableStateOf, som bestämmer beteendet vid jämförelse. structuralEquality() kontrollerar equals() — detta är standardbeteendet. referentialEquality() kontrollerar === (referensiell likhet). neverEqual() betraktar varje tilldelning som en ändring. Valet av policy påverkar om omkomponering startas vid tilldelning av samma värde.

Syntax och sätt att deklarera mutableStateOf

Det enklaste sättet att deklarera observerbart tillstånd är att använda mutableStateOf med remember. Utan remember skulle en ny State skapas vid varje omkomponering och alla tidigare ändringar skulle gå förlorade. remember garanterar att samma MutableState överlever en serie omkomponeringar så länge Composable-funktionen finns kvar i kompositionen.

kotlin
@Composable
fun Counter() {
    // Utan delegering: läsning/skrivning via .value
    val count = remember { mutableStateOf(0) }
    Button(onClick = { count.value++ }) {
        Text("Count: ${count.value}")
    }
}

@Composable
fun CounterDelegated() {
    // Med delegering: var + by = Property Delegation
    var count by remember { mutableStateOf(0) }
    Button(onClick = { count++ }) {
        Text("Count: $count")
    }
}

Skillnaden mellan de två varianterna är syntaktisk. Property Delegation (by) använder Kotlin-konventionen: kompilatorn genererar anrop till getValue() och setValue() för läsning och skrivning. Detta är likvärdigt med direkt åtkomst till count.value, men ser ut som att arbeta med en vanlig variabel. Båda varianterna är funktionellt identiska: Compose spårar läsning i gettern och skrivning i settern oavsett skrivform.

FormKodLäsningSkrivning
Utan delegeringval count = mutableStateOf(0)count.valuecount.value = n
Med delegeringvar count by mutableStateOf(0)countcount = n

Delegerade egenskaper och var

Mekanismen för delegerade egenskaper i Kotlin är inte en Compose-funktion, utan en inbyggd språkmöjlighet. Vilken klass som helst kan implementera operatorerna getValue(thisRef, property) och setValue(thisRef, property, value), varefter dess instans kan användas med nyckelordet by. MutableState fungerar precis så: getValue returnerar det aktuella värdet och setValue tilldelar ett nytt.

Viktig skillnad: val och var. mutableStateOf kan tilldelas både val och var. I fallet med val (val count = mutableStateOf(0)) är själva MutableState-objektet oföränderligt, men dess egenskap value kan ändras. I fallet med var (var count by mutableStateOf(0)) skapar delegeringen en illusion av att arbeta med en primitiv typ, men i verkligheten anropar settern setValue på MutableState. Valet mellan val och var är ett val mellan explicit och implicit åtkomst till .value.

State Delegation är syntaktiskt socker som förenklar koden men inte ändrar mekaniken. Kotlin-kompilatorn översätter var x by mutableStateOf(0) till getter/setter som anropar mutableStateOf.getValue() och mutableStateOf.setValue(). I den genererade bytekoden finns ingen skillnad mellan val och var med by — båda fungerar genom samma MutableState-behållare.

kotlin
    // Anpassad delegering för Compose State
class ValidatedState<T>(initialValue: T) {
    private val state = mutableStateOf(initialValue)

    operator fun getValue(thisRef: Any?, property: KProperty<*>) = state.value

    operator fun setValue(thisRef: Any?, property: KProperty<*>, value: T) {
        if (value != state.value) {
            state.value = value
        }
    }
}

@Composable
fun Test() {
    var text by remember { ValidatedState("") }
}

Snapshot-systemet: hur mutableStateOf fungerar internt

Snapshot är en mekanism i Compose Runtime som säkerställer läskonsistens för State vid parallella ändringar. När en Composable-funktion läser mutableStateOf registrerar snapshoten det aktuella värdet. Om en annan ändring skriver till samma State under kompositionen ser snapshoten skrivningen men tillåter inte läsning av inkonsistent data — läsning returnerar alltid värdet som är aktuellt vid snapshotens start.

När settern mutableStateOf.value = newValue anropas startar Compose Runtime inte omedelbart omkomponering. Istället registreras ändringen i den aktuella snapshoten. När snapshoten tillämpas (vid ramgränsen) går Compose igenom listan över ändrade State och markerar läskomponenterna som Invalid. Först i nästa ram startas omkomponeringen. Detta garanterar att UI inte ritas om dussintals gånger vid kaskadförändringar.

Globala och lokala snapshoter: som standard fungerar mutableStateOf i en global snapshot som tillämpas automatiskt. En lokal snapshot kan skapas via Snapshot.takeSnapshot() för isolerad läsning utan sidoeffekter. Detta används inuti Modifier, där State behöver läsas men inte prenumereras på ändringar. Detta tillvägagångssätt optimerar prestanda och förhindrar oväntade omkomponeringar.

Exempel på användning av mutableStateOf

Låt oss betrakta ett verkligt scenario — ett inloggningsformulär med tre fält: e-post, lösenord och laddningsstatus. Alla tre fälten använder mutableStateOf, men med olika policy och olika nästling. e-post använder delegering, lösenord — direkt åtkomst.

kotlin
data class LoginState(
    val email: String = "",
    val password: String = "",
    val isLoading: Boolean = false,
    val error: String? = null
)

@Composable
fun LoginForm(onLogin: (String, String) -> Unit) {
    // Enskilt State för formulär, policy = referentialEquality
    var formState by remember {
        mutableStateOf(LoginState(), SnapshotMutationPolicy.referentialEquality())
    }

    val isValid = remember(formState) {
        formState.email.contains("@") && formState.password.length() >= 6
    }

    Column(modifier = Modifier.padding(16.dp)) {
        OutlinedTextField(
            value = formState.email,
            onValueChange = { formState = formState.copy(email = it) },
            label = { Text("E-post") }
        )
        OutlinedTextField(
            value = formState.password,
            onValueChange = { formState = formState.copy(password = it) },
            label = { Text("Lösenord") },
            visualTransformation = PasswordVisualTransformation()
        )
        Button(
            onClick = { onLogin(formState.email, formState.password) },
            enabled = isValid
        ) {
            Text("Logga in")
        }
    }
}

I detta exempel används mutableStateOf med en anpassad dataklass LoginState och policy referentialEquality. Detta betyder att omkomponering endast startas vid tilldelning av en ny LoginState-instans via copy(). isValid beräknas baserat på formState och omräknas endast när det ändras. Detta tillvägagångssätt ger tydlig kontroll över omkomponeringar: varje formulärfält ändras endast genom att skapa en ny kopia.

Vanliga frågor

Vad är skillnaden mellan mutableStateOf och StateFlow?

mutableStateOf är en Compose-specifik behållare som fungerar inuti snapshoter. StateFlow kommer från kotlinx.coroutines.flow och är inte bunden till Compose. mutableStateOf startar automatiskt omkomponering, StateFlow kräver collectAsState(). För UI-tillstånd inuti Composable är mutableStateOf att föredra.

Kan mutableStateOf användas utanför @Composable-funktioner?

Ja, mutableStateOf kan anropas utanför en Composable-funktion, men det kommer inte att spåras. För att reaktivitet ska fungera i UI måste State läsas inuti Composable. Många ViewModel använder MutableStateField (ett omslag över mutableStateOf) för att överföra tillstånd till UI via StateFlow.

Vad händer vid samtidig ändring av State från två trådar?

Snapshot-systemet garanterar konsistens: varje omkomponering ser konsekvent tillstånd vid snapshotens start. Ändringar från olika trådar tillämpas atomärt vid ramgränsen, vilket eliminerar race condition vid läsning inom en komposition.

Hur återställer man mutableStateOf till初始värdet?

Tilldela ett nytt värde: count.value = 0 (eller count = 0 vid delegering). Om fullständig återskapning av State behövs — använd remember med en nyckel: remember(key) { mutableStateOf(initial) } — när nyckeln ändras kommer State att skapas på nytt.

Påverkar mutableStateOf prestanda vid frekventa ändringar?

Composer använder snapshots som grupperar ändringar: även med hundra tilldelningar i en ram utförs omkomponering endast en gång. För mycket frekventa uppdateringar (animationer), använd Animatable eller animate*AsState — de är optimerade för ramuppdateringar.

Sammanfattning

  • mutableStateOf skapar en observerbar MutableState-behållare som övervakas av Compose Runtime
  • Delegering via by förenklar koden men ändrar inte State-mekaniken
  • Snapshot-systemet garanterar läskonsistens och förhindrar onödiga omkomponeringar
  • Policy bestämmer när en ändring anses betydande — structuralEquality, referentialEquality, neverEqual
  • remember är obligatoriskt för att bevara State mellan omkomponeringar inuti Composable
  • Rekommendation: använd mutableStateOf med delegering för UI-tillstånd och referentialEquality för dataklasser
  • Undvik: att skapa mutableStateOf utan remember — varje tilldelning kommer att skapa ett nytt objekt

Vi utvecklar en mobil applikation nyckelfärdigt

IT Sectr skapar iOS- och Android-applikationer för startups och företag sedan 2017. Vi ger dig råd och föreslår den bästa lösningen.

Diskutera projektet

Läs också