Чек-лист правильного Compose

Собираем весь курс в один практический чек-лист, по которому стоит сверяться при написании Compose-кода.

Хороший Compose-код — это предсказуемый поток данных, аккуратное состояние и узкая область перерисовки.

Состояние

  • Изменяемое состояние — только через remember { mutableStateOf(...) }.
  • Пользовательский ввод, который должен пережить поворот, — через rememberSaveable.
  • Логику и долгоживущие данные экрана — в ViewModel, наружу отдавать read-only StateFlow.
  • Подписка на поток — через collectAsState.

Поток данных

  • Данные текут вниз через параметры, события — вверх через колбэки (однонаправленный поток).
  • Низкоуровневые компоненты делайте stateless и поднимайте состояние (state hoisting) ровно до нужного уровня.
  • Состояние читайте как можно ниже по дереву, чтобы сузить recomposition.

UI и раскладка

  • Размеры — в dp, шрифты — в sp.
  • Помните про порядок модификаторов: он влияет на результат.
  • Каркас экрана — на Scaffold; не забывайте применять innerPadding.
  • Цвета — через роли темы (primary, surface, onPrimary), а не жёсткие значения.

Списки и эффекты

  • Длинные списки — LazyColumn/LazyRow, для изменяемых списков задавайте key.
  • Побочные эффекты — только через effect handlers: LaunchedEffect для запуска при входе, rememberCoroutineScope для реакции на события.
  • Никаких запросов и логов в голом теле composable.

Мини-пример «всё вместе»

@Composable
fun NotesScreen(viewModel: NotesViewModel = viewModel()) {
    val notes by viewModel.notes.collectAsState()
    Scaffold(
        topBar = { TopAppBar(title = { Text("Заметки") }) }
    ) { padding ->
        LazyColumn(modifier = Modifier.padding(padding)) {
            items(notes, key = { it.id }) { note ->
                Text(text = note.title, modifier = Modifier.padding(16.dp))
            }
        }
    }
}

В этом экране собрано почти всё: ViewModel + StateFlow + collectAsState, каркас Scaffold с TopAppBar, ленивый список с ключами и модификаторы с отступами.

Как работает под капотом

Каждый пункт чек-листа опирается на одну идею: Compose перерисовывает то, что зависит от изменившегося состояния. Узкое чтение состояния, стабильные параметры, ленивые списки и эффекты вне тела — всё это способы помочь движку перерисовывать как можно меньше и предсказуемее. Понимая механизм recomposition, вы выводите эти правила сами, а не заучиваете.

Частые ошибки (сводно)

  • Состояние без remember — «несчитающий» счётчик.
  • Побочные эффекты в теле composable — повторяются на каждой перерисовке.
  • Списки без ключей и большие Column вместо LazyColumn — тормоза.
  • Жёсткие цвета вместо ролей темы — сломанная тёмная тема.

Итог

  • Состояние — через remember/rememberSaveable/ViewModel, поток данных однонаправленный.
  • Список — ленивый и с ключами; эффекты — через effect handlers.
  • Сужайте область recomposition: ниже читайте состояние, держите параметры стабильными.
Проверьте себя
1. Какой набор инструментов корректно покрывает состояние экрана со списком в Compose?
AОбычные переменные без remember и Column
BViewModel + StateFlow + collectAsState, Scaffold и LazyColumn с key
CТолько rememberSaveable для всего
DXML-разметка и findViewById
2. Где НЕ должны находиться побочные эффекты (запросы, логи)?
AВ LaunchedEffect
BВ голом теле composable-функции
CВ rememberCoroutineScope при клике
DВ методах ViewModel