LaunchedEffect vs SideEffect vs DisposableEffect

Compose effects connect declarative UI to work outside composition. LaunchedEffect runs suspend work, SideEffect publishes successful composition results, and DisposableEffect registers something that must be unregistered.

Practical guidance

  • Use LaunchedEffect for lifecycle-bound coroutines.
  • Use DisposableEffect for listeners, observers and callbacks with cleanup.
  • Use SideEffect to synchronize non-Compose state after composition succeeds.
  • Choose keys that describe when the effect must restart.

Working example

LaunchedEffect(userId) { viewModel.load(userId) }

DisposableEffect(lifecycleOwner) {
    val observer = LifecycleEventObserver { _, event -> analytics.record(event) }
    lifecycleOwner.lifecycle.addObserver(observer)
    onDispose { lifecycleOwner.lifecycle.removeObserver(observer) }
}

SideEffect { analytics.setScreenName(screenName) }

Common mistakes

  • Launching a coroutine directly in a composable body starts it on every recomposition.
  • Using Unit as a key creates an effect for the composable lifetime, not forever.
  • DisposableEffect must release every resource it registers.

Key takeaway

Pick the API from the work’s lifecycle and cleanup needs. Effects are escape hatches, so keep them narrow and observable.

Leave a Comment

Your email address will not be published. Required fields are marked *

Scroll to Top