Novo Dimaporo
03/30/2025, 7:33 AMprivate val loadTrigger = MutableSharedFlow<Long>()
private var tState = TransactionsState()
@OptIn(ExperimentalCoroutinesApi::class)
val transactionsState = combine(
currentUser.filterNotNull(),
loadTrigger.onStart { emit(0) }
) { user, delayDuration -> user to delayDuration }
.filterNot { tState.isLoading }
.onEach { tState = tState.copy(loadingPage = tState.page + 1, isLoading = true) }
.flatMapLatest { (user, delayDuration) ->
delay(delayDuration)
observeTransactionDetails(
count = tState.loadingPage * PAGE_SIZE,
userId = user.uid,
accountId = accountId)
}
.map { result ->
tState.copy(
transactions = TransactionProcessor
.toListItems(result),
page = tState.loadingPage,
isEndOfList = result.isEmpty(),
isLoading = false
)
}
.onEach { tState = it }
.stateIn(
scope = viewModelScope,
started = SharingStarted.Eagerly,
initialValue = TransactionsState()
)
fun loadNext() {
viewModelScope.launch { loadTrigger.emit(500) }
}
I tried using runningFold at first, but I need to have access to the current state to debounce the request to load more if it is still loading a page.
I did not use paging 3 because I am working on a KMM project.
Let me know if you need more context to understand this snippet.Chrimaeon
03/30/2025, 10:22 AMUjjwal Sai
03/30/2025, 5:28 PMFlow quite well, but relying on tState as a mutable variable outside the flow chain can lead to subtle issues — especially with rapid emissions or concurrency.
A more idiomatic approach would be to keep state within the flow itself, using something like runningFold or scan, which gives you access to the previous state and emits the new one reactively.
This way, you can handle isLoading, page, and transactions updates in a clean, reactive way without needing to manually track tState.Novo Dimaporo
03/31/2025, 2:05 AMisLoading field of the state because the state is only inside this operator and to the collector, I need isLoading to block the succeeding request to load more items. I was eyeing if I can use CONFLATED channel.Novo Dimaporo
03/31/2025, 2:15 AMChrimaeon
03/31/2025, 5:49 AMUjjwal Sai
03/31/2025, 5:49 AMNovo Dimaporo
03/31/2025, 6:49 AM