LaunchedEffect and Keys

LaunchedEffect(key) { } runs a coroutine when its call enters the composition, restarts it when the key changes and cancels it on leave. LaunchedDemo loads the current book; Next book changes it:

EffectDemos.kt: one load per book idKotlin
  LaunchedEffect(book.id) {                     // a new coroutine whenever the key changes
    Log.d(FX, "load ${book.id}: start")
    try {
      delay(1500)                               // stands in for a network call
      Log.d(FX, "load ${book.id}: done")
    } catch (e: CancellationException) {
      Log.d(FX, "load ${book.id}: cancelled"); throw e   // always rethrow cancellation
    }
  }

After the first load, Next book is tapped twice, half a second apart:

Output of 91
D/BookNestFx: load 1: start
D/BookNestFx: load 1: done
D/BookNestFx: load 2: start
D/BookNestFx: load 2: cancelled
D/BookNestFx: load 3: start
D/BookNestFx: load 3: done

React 7,897 needs an AbortController for this race; here structured concurrency (Structured Concurrency) cancelled the stale load. LaunchedEffect(Unit) runs once, like [].