Код-ревью Middle Compose: композиция и рекомпозиция обновлено

Код-ревью экрана списка на Compose

Вопрос

Проведи ревью экрана со списком заказов на Compose. Найди ошибки и проблемы производительности.

@Composable
fun OrdersScreen(viewModel: OrdersViewModel) {
    val state = viewModel.state.collectAsState().value
    viewModel.loadOrders()
    var expandedId by mutableStateOf<Long?>(null)
    val sorted = state.orders.sortedByDescending { it.createdAt }

    Column(Modifier.verticalScroll(rememberScrollState())) {
        sorted.forEach { order ->
            OrderRow(
                order = order,
                expanded = order.id == expandedId,
                onClick = { expandedId = order.id },
            )
        }
    }
}

data class Order(val id: Long, var status: String, val createdAt: Long)

Коротко

Типичный набор ошибок Compose: побочный эффект (загрузка) в теле функции, состояние без remember, тяжёлые вычисления без кеша, не ленивый список, нестабильная модель и сбор потока без учёта жизненного цикла.

Что должен найти ревьюер

  1. Производительностьстрока 3
    collectAsState без учёта жизненного цикла: сбор продолжается в фоне; нужен collectAsStateWithLifecycle
  2. Ошибкастрока 4
    Вызов loadOrders прямо в теле: запрос уходит при каждой рекомпозиции; перенести в init ViewModel или LaunchedEffect(Unit)
  3. Ошибкастрока 5
    mutableStateOf без remember: состояние сбрасывается при каждой рекомпозиции, раскрытие не работает
  4. Производительностьстрока 6
    Сортировка в теле на каждой рекомпозиции; делать во ViewModel или remember(state.orders)
  5. Производительностьстрока 8
    Column с forEach компонует все заказы сразу; для длинного списка нужен LazyColumn с key = { it.id }
  6. Производительностьстрока 19
    var в data class делает Order нестабильным, OrderRow не будет пропускаться; сделать поле val

Разбор

Типичный набор ошибок Compose: побочный эффект (загрузка) в теле функции, состояние без remember, тяжёлые вычисления без кеша, не ленивый список, нестабильная модель и сбор потока без учёта жизненного цикла. Правильная версия: загрузка во ViewModel, collectAsStateWithLifecycle, var expandedId by rememberSaveable { mutableStateOf<Long?>(null) }, сортировка во ViewModel, LazyColumn с items(orders, key = { it.id }) и неизменяемая модель.

Ответьте сами, а не прочитайте

В тренажёре вопрос попадёт в повторения и вернётся, когда начнёт забываться. Плюс билеты с зачётом: 20 вопросов, не больше 2 ошибок.