I tried to setup correct API call with debounce. Now I have function in ViewModel which call API search request with delay (debounce) and unique (latest) value, but as many as there are changes in the TextField in one time after debounce
This my code:
UI:
val searchedText by viewModel.searchText.collectAsState()
OutlinedTextField(
modifier = Modifier
.fillMaxWidth()
.padding(15.dp),
value = searchedText,
onValueChange = { newText ->
viewModel.updateSearchedText(newText)
if (newText.isNotEmpty()) {
viewModel.getSearchedNotifications(5, 0)
} else {
viewModel.getAllNotifications(5, 0)
}
},
ViewModel:
private val _searchText = MutableStateFlow("")
val searchText: StateFlow<String> = _searchText
@OptIn(FlowPreview::class, ExperimentalCoroutinesApi::class)
fun getSearchedNotifications(
take: Int,
skip: Int
) {
viewModelScope.launch {
_searchText
.debounce(2000L)
.distinctUntilChanged()
.collectLatest { searched ->
val response = notificationsRepository.getNotifications(
take,
skip,
searched
)
when (response) {
is Resource.Success -> {
_notifications.update {
response.data
}
}
is Resource.Error -> {
}
else -> {}
}
}
}
}
For example, I wrote in TextField "acc", delay 2 second and after that I had 3 API requests with same parametr acc. Expected that must be only one request with this parametr after user cancel entering and delay will overed.
As mentioned in the Leviathan's comment, TextFields are very buggy with flows, so you should use State instead of StateFlow to hold your TextField's text.
And you are creating a new flow every time your function is called, which means you have multiple flows updating your
_notificationsState or Flow.Instead, you can use your function to update a flow or flows that feed into a single flow that you create only once and make persistent using
shareInorstateIn. Something like this: