Hi all, I have an architecture issue with a compos...
# compose
g
Hi all, I have an architecture issue with a composable and a Kotlin Flow from a ViewModel. In my ViewModel, I have a flow which observes any changes in a room database to emit a data with a delay. Here a small example of my ViewModel:
Copy code
fun myFunc(input: Input) = flow {
  myDao.get().collect {
    it.forEach {
      emit(it.data)
      delay(it.delayTime)
    }
  }
}
In my composable, I have something like this:
Copy code
@Composable
fun MyComposable(input: Input) {
  val myViewModel: MyViewModel = viewModel()
  val data = myViewModel.myFunc(input).collectAsState()
  AnotherComposable(data = data.value)
}
The issue is: When I emit new data from my flow, compose collect the data and recompose itself because the state has been updated but due to this recomposition, it recall
myFunc
function, cancel the previous execution of the flow, collect data from database, emit values and loop a long time like this. How can I change my code to avoid this loop? There is any good practice for my usecase? Thanks in advance!
For now, the only workaround I found is this: Create a StateFlow in my ViewModel to emit my data and to avoid return a flow in
myFunc
and in my composable:
Copy code
@Composable
fun MyComposable(input: Input) {
  val myViewModel: MyViewModel = viewModel()
  val inputState = remember { mutableStateOf(input.id) }
  onActive {
    myViewModel.myFunc(input)
  }
  onCommit {
    if (inputState.value != input.id) {
      myViewModel.myFunc(input)
      inputState.value = input.id
    }
  }
  val data = myViewModel.myStateFlow.collectAsState()
  AnotherComposable(data = data.value)
}
k
This seems like a SideEffect and you should make use of one of them for your use-case. 1) I believe using
produceState
will make sure that
myFunc()
will be executed only once. 2) using kotlin's
by
to get the value out of flow would also make some difference (atleast I use it this way) 3) If you know some
subject
that causes the values being emitted via flow, you can use
LaunchedEffect
to call
myFunc
every time that subject changes Also, I believe there should be no infinite loop by looking at the give code block as you're not using
data.value
in
MyComposable
anywhere and any changes in
data.value
should only recompose the
AnotherComposable
.
g
Thanks @Kshitij Patil, LaunchedEffect is exactly what I'm looking for! But agree with you,
data.value
should only recompose the
AnotherComposable