Что такое State Hoisting? Почему это ключевая практика в Compose?

State hoisting в Compose — это просто поднятие состояния наверх по дереву, из дочернего @Composable в его родителя.

Формула очень простая:

Компонент не хранит state, а получает его «сверху» и сообщает о изменениях «наверх».

И это одна из ключевых практик в Compose, потому что она обеспечивает один источник истины, повторное использование, тестируемость и предсказуемость UI.

Что такое State Hoisting на примере

Плохой пример без hoisting-а — компонент сам хранит состояние

@Composable
fun Counter() {
    var count by remember { mutableStateOf(0) }

    Button(onClick = { count++ }) {
        Text("Count = $count")
    }
}

Здесь Counter сам хранит своё состояние и родитель никак не может контролировать count:

  • не может сбросить его,
  • не может задать начальное значение,
  • не может синхронизировать с другим стейтом.

Hoisted state — выносим state в родителя

@Composable
fun Counter(
    count: Int,
    onIncrement: () -> Unit
) {
    Button(onClick = onIncrement) {
        Text("Count = $count")
    }
}

А стейт теперь хранит родитель:

@Composable
fun CounterScreen() {
    var count by remember { mutableStateOf(0) }

    Counter(
        count = count,
        onIncrement = { count++ }
    )
}

Вот это и есть state hoisting:

  • состояние count поднято из Counter в CounterScreen
  • Counter стал stateless (управляемым извне)
  • он просто отрисовывает count и репортит события через callback

Почему это ключевая практика в Compose

  • Один источник истины (Single Source of Truth)
  • Лёгкое управление и переиспользование
  • Тестируемость
  • Унифицированный подход “state down, events up”

Что будет, если state не поднимать?

Типичные проблемы:

  • компонент невозможно контролировать снаружи (как TextView, которому нельзя сказать: “не меняй текст сам”)
  • state начинает дублироваться в нескольких местах
  • сложнее дебажить: “откуда взялось это значение?”
  • трудно привязать к ViewModel/Flow — придётся лепить костыли внизу

Опубликовано

в

от

Метки: