CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/maven-org-jetbrains-compose-runtime--runtime-desktop

Tree composition support and runtime infrastructure for Compose Multiplatform desktop applications with declarative UI development APIs.

Pending
Overview
Eval results
Files

state-management.mddocs/

State Management

Core state management APIs for creating reactive UI state that automatically triggers recomposition when values change. The Compose state system enables declarative UI updates through observable state holders.

Capabilities

State Interfaces

The fundamental interfaces for state management in Compose.

/**
 * Read-only state holder that can be observed by composables
 */
interface State<out T> {
    val value: T
}

/**
 * Mutable state holder that triggers recomposition when changed
 */
interface MutableState<T> : State<T> {
    override var value: T
}

Creating Mutable State

Create mutable state instances that trigger recomposition when their values change.

/**
 * Creates a mutable state holder with the specified initial value
 * @param value Initial value for the state
 * @param policy Mutation policy for detecting changes (default: structural equality)
 * @return MutableState instance
 */
fun <T> mutableStateOf(
    value: T,
    policy: SnapshotMutationPolicy<T> = structuralEqualityPolicy()
): MutableState<T>

Usage Examples:

import androidx.compose.runtime.*
import androidx.compose.runtime.derivedStateOf

@Composable
fun StateExample() {
    // Create mutable state
    val count = mutableStateOf(0)
    val text = mutableStateOf("Hello")
    
    // Access values
    Text("Count: ${count.value}")
    Text("Text: ${text.value}")
    
    // Update values
    Button(onClick = { count.value++ }) {
        Text("Increment")
    }
    
    Button(onClick = { text.value = "Updated!" }) {
        Text("Update Text")
    }
}

State Delegation

Use property delegation for cleaner syntax with state values.

/**
 * Delegate operator for reading state values
 */
operator fun <T> State<T>.getValue(
    thisObj: Any?,
    property: KProperty<*>
): T

/**
 * Delegate operator for writing mutable state values
 */
operator fun <T> MutableState<T>.setValue(
    thisObj: Any?,
    property: KProperty<*>,
    value: T
)

Usage Examples:

@Composable
fun DelegationExample() {
    // Using delegation with 'by' keyword
    var count by mutableStateOf(0)
    var isEnabled by mutableStateOf(true)
    var userName by mutableStateOf("")
    
    // Direct access without .value
    Text("Count: $count")
    Text("Enabled: $isEnabled")
    
    Button(
        onClick = { count++ },
        enabled = isEnabled
    ) {
        Text("Click me")
    }
    
    TextField(
        value = userName,
        onValueChange = { userName = it }
    )
}

Remember State

Preserve state across recompositions using the remember API.

/**
 * Remembers a value across recompositions
 * @param calculation Function to create the remembered value
 * @return The remembered value
 */
@Composable
fun <T> remember(calculation: () -> T): T

/**
 * Remembers a value with dependency keys for conditional invalidation
 * @param key1 Dependency key - value is recalculated when this changes
 * @param calculation Function to create the remembered value
 * @return The remembered value
 */
@Composable
fun <T> remember(key1: Any?, calculation: () -> T): T

/**
 * Remembers a value with multiple dependency keys
 */
@Composable
fun <T> remember(
    key1: Any?, 
    key2: Any?, 
    calculation: () -> T
): T

/**
 * Remembers a value with variable number of dependency keys
 */
@Composable
fun <T> remember(
    vararg keys: Any?, 
    calculation: () -> T
): T

Usage Examples:

@Composable
fun RememberExample(userId: String) {
    // Remember state across recompositions
    val counter by remember { mutableStateOf(0) }
    
    // Remember with key - recalculated when userId changes
    val userProfile by remember(userId) { 
        mutableStateOf(loadUserProfile(userId)) 
    }
    
    // Remember expensive computations
    val expensiveData by remember(userId) {
        mutableStateOf(performExpensiveCalculation(userId))
    }
    
    // Multiple keys
    val complexState by remember(userId, counter) {
        mutableStateOf(createComplexState(userId, counter))
    }
}

Mutation Policies

Control how the state system detects changes using mutation policies.

/**
 * Policy interface for detecting state mutations
 */
interface SnapshotMutationPolicy<T> {
    fun equivalent(a: T, b: T): Boolean
    fun merge(previous: T, current: T, applied: T): T?
}

/**
 * Built-in policy using structural equality (==)
 */
fun <T> structuralEqualityPolicy(): SnapshotMutationPolicy<T>

/**
 * Built-in policy using referential equality (===)
 */
fun <T> referentialEqualityPolicy(): SnapshotMutationPolicy<T>

/**
 * Policy that treats all values as different (always triggers updates)
 */
fun <T> neverEqualPolicy(): SnapshotMutationPolicy<T>

Usage Examples:

@Composable
fun PolicyExample() {
    // Default structural equality
    var items by mutableStateOf(listOf("a", "b", "c"))
    
    // Referential equality - only updates on reference change
    var objectState by mutableStateOf(
        MyObject("data"),
        referentialEqualityPolicy()
    )
    
    // Never equal - always triggers updates
    var alwaysUpdate by mutableStateOf(
        getCurrentTimestamp(),
        neverEqualPolicy()
    )
}

Saveable State

State that survives configuration changes and process death.

/**
 * Remembers state that can survive configuration changes
 * @param inputs Dependency keys for conditional restoration
 * @param saver Custom saver for non-primitive types
 * @param init Function to create initial value
 * @return Saveable state value
 */
@Composable
fun <T> rememberSaveable(
    vararg inputs: Any?,
    saver: Saver<T, out Any> = autoSaver(),
    init: () -> T
): T

Usage Examples:

import androidx.compose.runtime.saveable.rememberSaveable

@Composable
fun SaveableExample() {
    // Survives configuration changes
    var text by rememberSaveable { mutableStateOf("") }
    var count by rememberSaveable { mutableStateOf(0) }
    
    // Custom saver for complex objects
    var customObject by rememberSaveable(
        saver = CustomObjectSaver
    ) {
        mutableStateOf(CustomObject())
    }
    
    TextField(
        value = text,
        onValueChange = { text = it }
    )
    
    Button(onClick = { count++ }) {
        Text("Count: $count")
    }
}

Advanced State Management

Derived State

Create state that depends on other state values.

/**
 * Creates derived state that updates when dependencies change
 */
@Composable
fun <T> derivedStateOf(calculation: () -> T): State<T>

Usage Examples:

@Composable
fun DerivedStateExample() {
    var firstName by remember { mutableStateOf("") }
    var lastName by remember { mutableStateOf("") }
    
    // Derived state automatically updates when dependencies change
    val fullName by remember {
        derivedStateOf { "$firstName $lastName".trim() }
    }
    
    val isFormValid by remember {
        derivedStateOf { 
            firstName.isNotBlank() && lastName.isNotBlank() 
        }
    }
    
    Text("Full name: $fullName")
    Button(
        onClick = { saveUser(fullName) },
        enabled = isFormValid
    ) {
        Text("Save")
    }
}

State Production

Produce state from asynchronous sources.

/**
 * Produces state from a suspending producer function
 * @param initialValue Initial value while producer is running
 * @param producer Suspending function that produces values
 * @return State holding the produced value
 */
@Composable
fun <T> produceState(
    initialValue: T,
    vararg keys: Any?,
    producer: suspend ProduceStateScope<T>.() -> Unit
): State<T>

/**
 * Scope for producing state values
 */
interface ProduceStateScope<T> : MutableState<T>, CoroutineScope {
    suspend fun awaitDispose(onDispose: () -> Unit)
}

Usage Examples:

@Composable
fun ProduceStateExample(url: String) {
    // Produce state from async operation
    val imageState by produceState<ImageBitmap?>(null, url) {
        value = loadImageFromUrl(url)
    }
    
    val userData by produceState(UserData.Loading, userId) {
        try {
            value = UserData.Success(loadUser(userId))
        } catch (e: Exception) {
            value = UserData.Error(e.message)
        }
    }
    
    when (val data = userData) {
        is UserData.Loading -> CircularProgressIndicator()
        is UserData.Success -> UserProfile(data.user)
        is UserData.Error -> ErrorMessage(data.message)
    }
}

Install with Tessl CLI

npx tessl i tessl/maven-org-jetbrains-compose-runtime--runtime-desktop

docs

collections.md

composition.md

effects.md

index.md

state-management.md

tile.json