Skip to content

Changing the state quickly repeatedly doesn't update the list #105

@KevinSchildhorn

Description

@KevinSchildhorn

I am working on a list where once a re-order is performed, it goes to the backend and makes a call. If that call fails I expect it to revert back to the original state. I have the code here:

// ListViewModel

data class ListState(
  val items: List<ListItemUiState> = emptyList(),
  val previousItems: List<ListItemUiState> = emptyList(),
)
class ListViewModel : ViewModel() {

  private val _uiStateFlow: MutableStateFlow<ListState> = MutableStateFlow(ListState())
  val uiStateFlow: StateFlow<ListState> = _uiStateFlow.asStateFlow()

  fun onMove(from: Int, to: Int) {
    viewModelScope.launch(Dispatchers.IO) {
      _uiStateFlow.update {
        val newItems = it.items.move(from = from, to = to)
        it.copy(
          items = newItems,
          previousItems = it.items.toMutableList(),
        )
      }

      val success = false // PerformMoveOnBackend()

      _uiStateFlow.update {
        val newPlanItems = if (success) it.items else it.previousItems
        it.copy(
          items = newPlanItems,
          previousItems = emptyList(),
        )
      }
    }
  }
}

Here is my ReorderableColumn Code.

// MyView

val viewModel = ListViewModel()
val state by viewModel.uiStateFlow.collectAsState()

ReorderableColumn(
  list = state.items,
  onSettle = { fromIndex, toIndex ->
    viewModel.onMove(fromIndex, toIndex) }
  },
) { _, item, _ ->
  key(item.reorderId) { // UUID
    when (item) {
      is ListItemUiState.Section -> { Section(item.text) }
      is ListItemUiState.Item -> {
        Card(modifier = Modifier.longPressDraggableHandle(item.draggable)) {
            Text(item.title)
        }
      }
    }
  }
}

The problem is that if the call fails, then the StateFlow is reverted to its original state, however the Column doesn't update to reflect this. I'm guessing that it's not handling the latest state change, or however it's handling when it refreshes is causing an issue. Maybe an issue with the ReorderableListState? This might be because it's updating the state immediately (i.e. there's not enough time inbetween the two state updates), because if I add a delay after the backend call then it seems to work correctly.

Expectation:
I expect that the column matches the state no matter how often you update it

Actual:
It seems that the column is ignoring subsequent updates if they are performed too often. If you do two updates in a row, the reorder only picks up the first, where a normal list picks up the second.

Here is the visual evidence.

Screen_recording_20251002_121318.webm

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions