Chanzmao ʕ•ᴥ•ʔ Bear Blog

When Should You Use snapshotFlow in Jetpack Compose?

Jetpack Compose provides several ways to react to state changes. Among them, snapshotFlow is often misunderstood.

Many developers either overuse it or never use it at all.

The key idea is simple:

Use snapshotFlow when you need to convert Compose state into a Kotlin Flow and perform side effects.

If you’re only updating the UI, snapshotFlow is usually the wrong tool.

What snapshotFlow Actually Does

snapshotFlow observes Compose state and emits new values as a Flow whenever that state changes.

snapshotFlow {
    state.value
}

You can then use all Flow operators such as:

This makes it ideal for reacting to UI state changes with asynchronous operations.

Compose State
 snapshotFlow
    Flow
 Flow Operators
 Side Effects

The Most Common Use Case: Scroll Tracking

This is probably the most common real-world use of snapshotFlow.

LaunchedEffect(listState) {
    snapshotFlow { listState.firstVisibleItemIndex }
        .distinctUntilChanged()
        .collect { index ->
            analytics.trackScroll(index)
        }
}

Instead of updating UI, we’re observing scroll position and sending analytics events.

Other examples include:

Another popular pattern is search input handling.

Without debounce, every keystroke could trigger a network request.

LaunchedEffect(Unit) {
    snapshotFlow { query }
        .debounce(500)
        .distinctUntilChanged()
        .collect {
            viewModel.search(it)
        }
}

This combines Compose state with Flow operators naturally.

Monitoring Pager Changes

For paged UIs, you may want to know when the user navigates to a different page.

LaunchedEffect(pagerState) {
    snapshotFlow { pagerState.currentPage }
        .distinctUntilChanged()
        .collect {
            analytics.pageViewed(it)
        }
}

This is useful for:

Monitoring Bottom Sheet State

LaunchedEffect(sheetState) {
    snapshotFlow { sheetState.currentValue }
        .collect {
            analytics.logSheetState(it)
        }
}

Whenever the sheet expands, collapses, or changes state, the Flow emits a new value.

When derivedStateOf Is Better

A common mistake is using snapshotFlow for UI calculations.

Suppose you only want to show a button when the list is scrolled.

val showButton by remember {
    derivedStateOf {
        listState.firstVisibleItemIndex > 0
    }
}

This is a UI concern.

No Flow is required.

No side effects are involved.

derivedStateOf is simpler and more efficient.

snapshotFlow vs derivedStateOf

Purpose derivedStateOf snapshotFlow
UI state calculation
Side effects
Analytics
Debounce
Flow operators
API requests

A useful rule of thumb is:

Need to update UI?
→ derivedStateOf

Need a Flow?
→ snapshotFlow

A Common Anti-Pattern

Avoid using snapshotFlow just to update Compose state.

snapshotFlow { state }
    .collect {
        text = it
    }

Compose already observes state changes and automatically recomposes the UI.

Adding a Flow in the middle only increases complexity.

snapshotFlow vs LaunchedEffect

Many developers wonder whether they should use LaunchedEffect or snapshotFlow.

The answer depends on whether Flow operators are needed.

If you simply want to react immediately when a value changes, LaunchedEffect is usually enough.

LaunchedEffect(selectedTab) {
    loadData(selectedTab)
}

However, if you need operators such as debounce, filter, or distinctUntilChanged, snapshotFlow becomes a better fit.

LaunchedEffect(Unit) {
    snapshotFlow { selectedTab }
        .debounce(300)
        .distinctUntilChanged()
        .collect {
            loadData(it)
        }
}

A simple guideline is:

Immediate reaction
LaunchedEffect

Flow operators needed
snapshotFlow

Conclusion

snapshotFlow is not a replacement for Compose state management.

Instead, think of it as a bridge between Compose state and Kotlin Flow.

Use it when:

If your goal is simply to update the UI, derivedStateOf is often the better choice.

The simplest mental model is:

UI calculation
derivedStateOf

Side effects + Flow operators
snapshotFlow

Once you view snapshotFlow as a tool for side effects rather than UI state, its use cases become much clearer.

#Android #Jetpack Compose #Kotlin #Flow