SIDE EFFECTS IN JETPACK COMPOSE
When I started learning Jetpack Compose, one thing confused me a lot:
Why Side Effects Exist in Compose
- UI should only describe UI
- No API calls inside Text()
- No timers inside Button()
- No listeners attached directly to UI
- Background tasks
- One-time operations
- Cleanup logic
- Observers
LaunchedEffect – The Most Used One
What it really means
When should you use LaunchedEffect?
- API calls
- Delays
- Timers
- Background jobs
- One-time logic
Simple API Call Example
@Composable
fun ProfileScreen(userId: Int) {
var name by remember { mutableStateOf("Loading...") }
LaunchedEffect(userId) {
delay(1000) // fake API call
name = "User ID: $userId"
}
Text(text = name)
}What happens here?
- Screen opens → API runs
- User ID changes → API re-runs
- Screen closes → coroutine cancels automatically
Timer Example
LaunchedEffect(Unit) {
while (true) {
delay(1000)
seconds++
}
}
This is perfect for stopwatch and countdown timer apps.
SideEffect
What it actually does
SideEffect runs after every successful recomposition.
Meaning:
“UI updated, now perform a non-UI action.”
When to use SideEffect?
- Logging
- Analytics
- Updating external objects
Logging Example
@Composable
fun Counter(count: Int) {
SideEffect {
Log.d("Counter", "Count changed to $count")
}
Text(text = "Count: $count")
}
Important: This runs on every recomposition, so avoid heavy work here.
DisposableEffect
Why this API exists
Some things need cleanup, such as:
- Listeners
- Sensors
- Location updates
- Media players
DisposableEffect is designed exactly for this.
Real-world thinking
“Start something when the screen opens, stop it when the screen closes.”
Listener Example
@Composable
fun ConnectivityObserver() {
DisposableEffect(Unit) {
registerNetworkListener()
onDispose {
unregisterNetworkListener()
}
}
}
Compose guarantees cleanup, so memory leaks are avoided.
produceState
What problem it solves
Normally, async work needs:
- mutableStateOf
- LaunchedEffect
- manual state updates
produceState combines everything into one clean block.
Example
@Composable
fun DataScreen() {
val result by produceState(initialValue = "Loading") {
delay(1500)
value = "Data Loaded Successfully"
}
Text(text = result)
}
This approach is cleaner and beginner-friendly.
snapshotFlow
Simple explanation
snapshotFlow converts Compose state into a Kotlin Flow.
Meaning:
“Notify me only when this state actually changes.”
Where it is useful
- Scroll tracking
- Slider movement
- User interaction analytics
Example
LaunchedEffect(Unit) {
snapshotFlow { sliderValue }
.collect { value ->
Log.d("Slider", "Current value: $value")
}
}
Quick Comparison
| Side Effect API | Best Use Case |
|---|---|
| LaunchedEffect | API calls, timers |
| SideEffect | Logging, analytics |
| DisposableEffect | Cleanup logic |
| produceState | Async to State |
| snapshotFlow | Observe state changes |
Practice App: Stopwatch + Timer
If you really want to master Side Effects, build a simple Stopwatch + Timer app.
Features
- Start, pause, and reset stopwatch
- Countdown timer
- Proper lifecycle handling
Which API is used where?
| Feature | API |
|---|---|
| Stopwatch ticking | LaunchedEffect |
| Logging updates | SideEffect |
| Cleanup logic | DisposableEffect |
| Initial loading | produceState |
| Observing time changes | snapshotFlow |
Frequently Asked Questions (FAQ)
1. What are Side Effects in Jetpack Compose?Side Effects are special APIs in Jetpack Compose used to run non-UI logic such as API calls, timers, logging, and listeners. Compose UI should only describe UI, so Side Effects help us safely run background or lifecycle-aware code without breaking Compose rules.
2. Can I call an API directly inside a composable function?No. You should never call APIs directly inside composables because recomposition can trigger the call multiple times. Always use LaunchedEffect or produceState for API calls and async operations.
3. What is the difference between LaunchedEffect and SideEffect?LaunchedEffect is used for coroutine work like API calls, delays, and timers. SideEffect runs after every recomposition and is mainly used for logging or syncing external state. You should never use SideEffect for network or heavy tasks.
4. When should I use DisposableEffect?Use DisposableEffect when something needs cleanup. Examples include registering listeners, sensors, location updates, or media players. Compose automatically calls onDispose when the composable leaves the screen.
5. Is produceState better than LaunchedEffect?Both are useful. produceState is cleaner when you want to convert async data directly into State. LaunchedEffect is more flexible for complex logic and multiple side effects. Beginners usually find produceState easier to read.
6. What problem does snapshotFlow solve?snapshotFlow helps observe Compose state changes as a Kotlin Flow. It emits values only when the state actually changes, not on every recomposition. This is useful for scroll tracking, sliders, and analytics.
7. Are Side Effects safe for performance?Yes, when used correctly. Jetpack Compose automatically cancels coroutines and cleans resources when the UI leaves. Problems occur only when Side Effects are misused, such as running heavy work inside SideEffect.
8. Can I use multiple Side Effects in one composable?Yes. You can use multiple Side Effect APIs in the same composable if needed. Each one should have a clear responsibility, like one for API calls and another for cleanup.
9. Is it okay to use while(true) inside LaunchedEffect?Yes, but only for controlled use cases like timers or stopwatches. Always ensure the loop has a delay and depends on a key so Compose can cancel it safely when needed.
10. Which Side Effect should beginners learn first?Start with LaunchedEffect. It covers most real-world use cases like API calls and timers. After that, learn DisposableEffect and produceState.
11. Can Side Effects replace ViewModel?No. Side Effects handle lifecycle-aware logic inside composables. ViewModel is still recommended for business logic, data storage, and state sharing across screens. They work together, not as replacements.
12. What is the best practice for Side Effects in real apps?Keep UI simple. Move business logic to ViewModel. Use Side Effects only for lifecycle-aware tasks that depend on composition. This results in clean, stable, and maintainable apps.
Final Words
Side Effects are not optional in Jetpack Compose. They are required to build real-world apps safely.
Once you understand:
- When UI enters
- When UI updates
- When UI leaves
Side Effects will feel natural and easy.
Happy Coding π