Composables can recompose many times, so you can't just call APIs or start work directly in them. Side-effect APIs let you run such work safely and predictably.
LaunchedEffect — run when it enters the screen
@Composable
fun FeedScreen(vm: FeedViewModel = viewModel()) {
LaunchedEffect(Unit) { // runs once when first composed
vm.load()
}
// ...
}
rememberCoroutineScope — launch on an event
val scope = rememberCoroutineScope()
Button(onClick = { scope.launch { vm.refresh() } }) { Text("Refresh") }
LaunchedEffect(key)— restarts whenkeychanges.rememberCoroutineScope()— launch coroutines from callbacks.DisposableEffect— register/clean up listeners.
Common mistake: Never call suspend functions or start network requests directly in the composable body — use LaunchedEffect, or trigger via the ViewModel.
Summary
Side-effect APIs run non-UI work safely: LaunchedEffect on entry/key change, rememberCoroutineScope for events, DisposableEffect for cleanup.