Jetpack Compose Load Data (Flow.collectAsState) Common Mistakes (Compose Infinite Loop)

This is the data class to be used for data loading from firestore db.

If you are using flow to load initial data, you must make sure it only the fetch only run once.

class CardViewModel : ViewModel() {    val itemsFlow = flow {      val items = MutableList((1..100).random()) { index ->          index      }      emit(items)    }}

Put a timestamp to check if the data is only load once.

fun CardScreen(viewModel: CardViewModel = viewModel()) {    val items by viewModel.itemsFlow.collectAsState(initial = emptyList())    Text("Items: ${items.size}, Time: ${LocalTime.now()}")}

If you use a function, it will cause compose infinite loop (the timestamp will update forever).

class CardViewModel : ViewModel() {    private val db = Firebase.firestore    fun getItems() = flow {      val items = MutableList((1..100).random()) { index ->          index      }      emit(items)    }}
fun CardScreen(viewModel: CardViewModel = viewModel()) {    val items by viewModel.getItems().collectAsState(initial = emptyList())    Text("Items: ${items.size}, Time: ${LocalTime.now()}")}

If you must use a function, you need to call the function in LaunchedEffect.

fun CardScreen(viewModel: CardViewModel = viewModel()) {    var items by remember { mutableStateOf<List<Int>>( emptyList()) }    LaunchedEffect(true) { // only launch once        viewModel.getItems().collect {             items = it        }    }    Text("Items: ${items.size}, Time: ${LocalTime.now()}")}

Assuming you need to load initial data, and perform a fetch on every click of a button.

fun CardScreen(viewModel: CardViewModel = viewModel()) {    var refreshCount by remember { mutableStateOf(0) }    var items by remember { mutableStateOf<List<Int>>( emptyList()) }    LaunchedEffect(refreshCount) { // run if refreshCount is updated        // you can choose to generate items based on refreshCount        viewModel.getItems().collect {            items = it        }    }    // button click will     Button(onClick = { refreshCount += 1 }) {        Text("Refresh")    }    Text("Items: ${items.size}, Time: ${LocalTime.now()}")}

Refer to Jetpack Compose Load Data (Initial on Show) using Flow or Coroutines.

❤️ Is this article helpful?

Buy me a coffee ☕ or support my work via PayPal to keep this space 🖖 and ad-free.

Do send some 💖 to @d_luaz or share this article.

✨ By Desmond Lua

A dream boy who enjoys making apps, travelling and making youtube videos. Follow me on @d_luaz

👶 Apps I built

Travelopy - discover travel places in Malaysia, Singapore, Taiwan, Japan.