Reputation: 15
I'm new to Jetpack Compose and my problem is that I'm trying to get data (JSON) from the server after navigation and I'm getting an infinite loop with LaunchedEffect
.
My UI code :
@Composable
fun ListView(
viewModelItems: ItemsViewModel = viewModel(),
) {
var stateData = remember {
mutableStateOf(0)
}
if(stateData.value == 0) {
LaunchedEffect(Unit) {
viewModelItems.getList()
viewModelItems.state.collectLatest {
stateData.value = it.state
}
}
}
when(stateData.value){
...
}
I think this is a problem with stateData
because it is not updated after recomposition.
My ViewModel code :
class ItemsViewModel : ViewModel(){
private var listState = MutableStateFlow<ListState>(Loading(null, 0))
var state = listState.asStateFlow()
fun getList(){
val res = SkovService.getInstance().getList()
res.enqueue(object : Callback<Items?>{
override fun onResponse(call: Call<Items?>, response: Response<Items?>) {
listState.value = Success(response.body(), 1)
}
override fun onFailure(call: Call<Items?>, t: Throwable) {
listState.value = Error(null, -1)
call.cancel()
}
})
}
}
ListState is a sealed class
.
I've been trying to solve this problem for 1 week =D, if you know how to solve it, please help me.
Upvotes: 1
Views: 532
Reputation: 1205
As @commonsware said, you can avoid using the LaunchedEffect
and use the collectAsState
with the ListState
object itself. Then there will be no need for the -1, 0 and 1 within the ListState
class and you can just use the type of the ListState
within the when
clause
@Composable
fun ListView(
viewModelItems: ItemsViewModel = viewModel(),
) {
val stateData by viewModelItems.state.collectAsState()
when (stateData.value) {
is Loading -> { // render loading components }
is Error -> { // render error components }
is Success -> { // use state value received from response.body() to render the list }
}
And you would need to call viewModelItems.getList()
outside of this @Composable
, or you can call it in the init
block of the ItemsViewModel
Upvotes: 1