or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

composition-lifecycle.mdcomposition-local.mdeffects.mdindex.mdios-integration.mdsnapshot-system.mdstate-management.md

state-management.mddocs/

0

# State Management

1

2

Core state management functionality providing reactive state holders and automatic change detection. The state system enables building dynamic UIs that automatically recompose when data changes.

3

4

## Capabilities

5

6

### MutableState Creation

7

8

Creates mutable state holders that trigger recomposition when their values change.

9

10

```kotlin { .api }

11

/**

12

* Creates a MutableState<T> initialized with the given value

13

* @param value Initial value for the state

14

* @return MutableState that triggers recomposition on value changes

15

*/

16

fun <T> mutableStateOf(value: T): MutableState<T>

17

18

/**

19

* Creates a MutableState<T> with a specific SnapshotMutationPolicy

20

* @param value Initial value for the state

21

* @param policy Custom equality policy for change detection

22

* @return MutableState with custom mutation policy

23

*/

24

fun <T> mutableStateOf(

25

value: T,

26

policy: SnapshotMutationPolicy<T>

27

): MutableState<T>

28

```

29

30

**Usage Examples:**

31

32

```kotlin

33

import androidx.compose.runtime.*

34

35

@Composable

36

fun StateExample() {

37

// Basic mutable state

38

var counter by remember { mutableStateOf(0) }

39

var text by remember { mutableStateOf("") }

40

var isVisible by remember { mutableStateOf(true) }

41

42

// Custom objects

43

var user by remember { mutableStateOf(User("", "")) }

44

45

// Lists

46

var items by remember { mutableStateOf(listOf<String>()) }

47

}

48

49

data class User(val name: String, val email: String)

50

```

51

52

### Derived State

53

54

Creates computed state that recalculates when its dependencies change.

55

56

```kotlin { .api }

57

/**

58

* Creates a State<T> that recalculates when dependencies change

59

* @param calculation Function that computes the derived value

60

* @return State that automatically updates when dependencies change

61

*/

62

fun <T> derivedStateOf(calculation: () -> T): State<T>

63

64

/**

65

* Creates a State<T> with a custom SnapshotMutationPolicy

66

* @param policy Custom equality policy for change detection

67

* @param calculation Function that computes the derived value

68

* @return State with custom derived computation policy

69

*/

70

fun <T> derivedStateOf(

71

policy: SnapshotMutationPolicy<T>,

72

calculation: () -> T

73

): State<T>

74

```

75

76

**Usage Examples:**

77

78

```kotlin

79

@Composable

80

fun DerivedStateExample() {

81

var firstName by remember { mutableStateOf("") }

82

var lastName by remember { mutableStateOf("") }

83

84

// Derived state automatically recalculates when firstName or lastName change

85

val fullName by remember {

86

derivedStateOf { "$firstName $lastName".trim() }

87

}

88

89

val isValidName by remember {

90

derivedStateOf { fullName.length >= 2 }

91

}

92

93

TextField(value = firstName, onValueChange = { firstName = it })

94

TextField(value = lastName, onValueChange = { lastName = it })

95

Text("Full name: $fullName")

96

Button(enabled = isValidName) { Text("Submit") }

97

}

98

```

99

100

### State Interfaces

101

102

Core interfaces for state management.

103

104

```kotlin { .api }

105

/**

106

* Read-only state holder

107

*/

108

interface State<out T> {

109

/** Current value of the state */

110

val value: T

111

}

112

113

/**

114

* Mutable state holder that triggers recomposition on changes

115

*/

116

interface MutableState<T> : State<T> {

117

/** Current mutable value of the state */

118

override var value: T

119

120

/**

121

* Returns a new component1 for destructuring declarations

122

* @return Current value

123

*/

124

operator fun component1(): T

125

126

/**

127

* Returns a new component2 for destructuring declarations

128

* @return Setter function for the state

129

*/

130

operator fun component2(): (T) -> Unit

131

}

132

133

/**

134

* Default implementation of MutableState using the snapshot system

135

*/

136

interface SnapshotMutableState<T> : MutableState<T> {

137

/** The SnapshotMutationPolicy used by this state */

138

val policy: SnapshotMutationPolicy<T>

139

}

140

```

141

142

### Property Delegates

143

144

Kotlin property delegate support for convenient state access.

145

146

```kotlin { .api }

147

/**

148

* Property delegate getter for State<T>

149

* @param thisObj The object containing the property (unused)

150

* @param property Metadata about the property (unused)

151

* @return Current value of the state

152

*/

153

operator fun <T> State<T>.getValue(

154

thisObj: Any?,

155

property: KProperty<*>

156

): T

157

158

/**

159

* Property delegate setter for MutableState<T>

160

* @param thisObj The object containing the property (unused)

161

* @param property Metadata about the property (unused)

162

* @param value New value to set

163

*/

164

operator fun <T> MutableState<T>.setValue(

165

thisObj: Any?,

166

property: KProperty<*>,

167

value: T

168

): Unit

169

```

170

171

**Usage Examples:**

172

173

```kotlin

174

@Composable

175

fun PropertyDelegateExample() {

176

// Using property delegates with 'by'

177

var name by remember { mutableStateOf("") }

178

var age by remember { mutableStateOf(0) }

179

180

// Equivalent to:

181

// val nameState = remember { mutableStateOf("") }

182

// var name: String

183

// get() = nameState.value

184

// set(value) { nameState.value = value }

185

}

186

```

187

188

### Snapshot Flow Integration

189

190

Convert state reads into Kotlin coroutine Flows.

191

192

```kotlin { .api }

193

/**

194

* Creates a Flow that emits the result of block whenever observed state changes

195

* @param block Function that reads state and produces values

196

* @return Flow that emits when any observed state changes

197

*/

198

fun <T> snapshotFlow(block: () -> T): Flow<T>

199

```

200

201

**Usage Examples:**

202

203

```kotlin

204

@Composable

205

fun FlowIntegrationExample() {

206

var searchQuery by remember { mutableStateOf("") }

207

208

LaunchedEffect(Unit) {

209

snapshotFlow { searchQuery }

210

.debounce(300)

211

.collect { query ->

212

if (query.isNotEmpty()) {

213

performSearch(query)

214

}

215

}

216

}

217

}

218

```

219

220

### Persistent State Management

221

222

State management that survives process death and configuration changes, essential for iOS applications.

223

224

```kotlin { .api }

225

/**

226

* Creates persistent state that survives process death and configuration changes

227

* Equivalent to remember but persists across app restarts

228

* @param value Initial value for the state

229

* @param saver Custom Saver for serialization, uses auto-saver if null

230

* @return MutableState that persists across process death

231

*/

232

@Composable

233

fun <T> rememberSaveable(

234

vararg inputs: Any?,

235

saver: Saver<T, out Any>? = null,

236

init: () -> T

237

): T

238

239

/**

240

* Creates persistent mutable state with initial value

241

* @param value Initial value for the state

242

* @param saver Custom Saver for serialization

243

* @return MutableState that persists across process death

244

*/

245

@Composable

246

fun <T> rememberSaveable(

247

value: T,

248

saver: Saver<T, out Any>? = null

249

): MutableState<T>

250

```

251

252

**Usage Examples:**

253

254

```kotlin

255

@Composable

256

fun PersistentStateExample() {

257

// Survives iOS app backgrounding and termination

258

var userName by rememberSaveable { mutableStateOf("") }

259

var userId by rememberSaveable { mutableStateOf(0) }

260

261

// Custom object with custom saver

262

var userProfile by rememberSaveable(

263

saver = UserProfileSaver

264

) { mutableStateOf(UserProfile()) }

265

266

TextField(

267

value = userName,

268

onValueChange = { userName = it },

269

label = { Text("Username") }

270

)

271

}

272

273

object UserProfileSaver : Saver<UserProfile, Bundle> {

274

override fun restore(value: Bundle): UserProfile? =

275

UserProfile.fromBundle(value)

276

277

override fun SaverScope.save(value: UserProfile): Bundle? =

278

value.toBundle()

279

}

280

```

281

282

### Async State Production

283

284

Create state from asynchronous data sources like network calls or databases.

285

286

```kotlin { .api }

287

/**

288

* Creates state that is produced by an async operation

289

* @param initialValue Initial value while async operation is running

290

* @param key1 Key that triggers recreation of the producer

291

* @param producer Suspend function that produces the state value

292

* @return State that updates when async operation completes

293

*/

294

@Composable

295

fun <T> produceState(

296

initialValue: T,

297

key1: Any?,

298

producer: suspend ProduceStateScope<T>.() -> Unit

299

): State<T>

300

301

/**

302

* Scope for produceState operations

303

*/

304

interface ProduceStateScope<T> : MutableState<T>, CoroutineScope {

305

/** Awaits the coroutine to complete before disposing */

306

suspend fun awaitDispose(onDispose: () -> Unit)

307

}

308

```

309

310

**Usage Examples:**

311

312

```kotlin

313

@Composable

314

fun AsyncStateExample(userId: String) {

315

val userState by produceState(

316

initialValue = User.Empty,

317

key1 = userId

318

) {

319

// Suspend function that loads user data

320

value = userRepository.loadUser(userId)

321

}

322

323

val networkState by produceState(

324

initialValue = NetworkState.Loading

325

) {

326

try {

327

val data = apiService.fetchData()

328

value = NetworkState.Success(data)

329

} catch (e: Exception) {

330

value = NetworkState.Error(e.message)

331

}

332

}

333

334

when (networkState) {

335

is NetworkState.Loading -> LoadingIndicator()

336

is NetworkState.Success -> DataDisplay(networkState.data)

337

is NetworkState.Error -> ErrorMessage(networkState.message)

338

}

339

}

340

```

341

342

### Flow to State Conversion

343

344

Convert Kotlin coroutine Flows to Compose State for reactive UI updates.

345

346

```kotlin { .api }

347

/**

348

* Collects values from a Flow and represents them as State

349

* @param initial Initial value before first emission

350

* @param context CoroutineContext for collection, uses current recomposition context by default

351

* @return State that reflects the latest Flow emission

352

*/

353

@Composable

354

fun <T> Flow<T>.collectAsState(

355

initial: T,

356

context: CoroutineContext = EmptyCoroutineContext

357

): State<T>

358

359

/**

360

* Collects values from a Flow as State with lifecycle awareness

361

* @param initial Initial value before first emission

362

* @param lifecycle Lifecycle to respect for collection

363

* @param minActiveState Minimum lifecycle state for active collection

364

* @param context CoroutineContext for collection

365

* @return State that reflects the latest Flow emission

366

*/

367

@Composable

368

fun <T> Flow<T>.collectAsStateWithLifecycle(

369

initial: T,

370

lifecycle: Lifecycle,

371

minActiveState: Lifecycle.State = Lifecycle.State.STARTED,

372

context: CoroutineContext = EmptyCoroutineContext

373

): State<T>

374

```

375

376

**Usage Examples:**

377

378

```kotlin

379

@Composable

380

fun FlowStateExample() {

381

val viewModel: UserViewModel = viewModel()

382

383

// Collect Flow as State

384

val users by viewModel.usersFlow.collectAsState(initial = emptyList())

385

val isLoading by viewModel.loadingFlow.collectAsState(initial = false)

386

387

// Display users

388

LazyColumn {

389

items(users) { user ->

390

UserItem(user = user)

391

}

392

}

393

394

if (isLoading) {

395

LoadingOverlay()

396

}

397

}

398

399

class UserViewModel : ViewModel() {

400

private val _users = MutableStateFlow<List<User>>(emptyList())

401

val usersFlow: StateFlow<List<User>> = _users.asStateFlow()

402

403

private val _loading = MutableStateFlow(false)

404

val loadingFlow: StateFlow<Boolean> = _loading.asStateFlow()

405

}

406

```

407

408

## Advanced State Management

409

410

### Custom Mutation Policies

411

412

```kotlin { .api }

413

/**

414

* Policy for determining when state changes should trigger recomposition

415

*/

416

interface SnapshotMutationPolicy<T> {

417

/**

418

* Determines if the current and new values are equivalent

419

* @param a Current value

420

* @param b New value

421

* @return true if values are equivalent and shouldn't trigger recomposition

422

*/

423

fun equivalent(a: T, b: T): Boolean

424

425

/**

426

* Merges conflicting changes during snapshot conflicts

427

* @param previous Previous value

428

* @param current Current value

429

* @param applied Value being applied

430

* @return Merged value or null if merge is not possible

431

*/

432

fun merge(previous: T, current: T, applied: T): T?

433

}

434

435

/** Built-in policies */

436

object SnapshotMutationPolicy {

437

/** Uses structural equality (==) for comparison */

438

fun <T> structuralEquality(): SnapshotMutationPolicy<T>

439

440

/** Uses referential equality (===) for comparison */

441

fun <T> referentialEquality(): SnapshotMutationPolicy<T>

442

443

/** Never considers values equivalent, always triggers recomposition */

444

fun <T> neverEqual(): SnapshotMutationPolicy<T>

445

}

446

```

447

448

## Performance Considerations

449

450

- **State Scoping**: Keep state as close as possible to where it's used

451

- **Derived State**: Use `derivedStateOf` instead of `remember` for computed values

452

- **State Hoisting**: Move state up the composition tree only when needed for sharing

453

- **Mutation Policies**: Consider custom policies for complex objects to avoid unnecessary recompositions