State Hoisting: zvedání stavu a jednosměrný tok dat v Compose

Autor: IT Sectr Publikováno: 2026-06-28 Doba čtení: 8 min

State Hoisting — je vzor v Jetpack Compose, při kterém je stav vyjmut z podřízené Composable funkce do nadřazené a podřízená získává data prostřednictvím parametrů a informuje o změnách pomocí callbacků. Jedná se o implementaci principu jednosměrného toku dat (UDF), kdy stav stoupá nahoru a události klesají dolů. Podle Google Android Developers, 2026 činí State Hoisting komponenty znovupoužitelnými, testovatelnými a předvídatelnými.

Hlavní body

  • State Hoisting přesouvá stav z podřízené komponenty do nadřazené
  • UDF (Unidirectional Data Flow) — stav teče dolů, události nahoru
  • Parametry podřízené komponenty: hodnota (T) + lambda (T) -> Unit
  • Znovupoužití — zvednutý stav umožňuje použít stejnou funkci s různými zdroji
  • Testování — State Hoisting zjednodušuje unit testy izolováním logiky od UI

Co je State Hoisting v Jetpack Compose

State Hoisting (zvedání stavu) — je vzor, při kterém Composable funkce nevlastní stav, ale získává jej zvenčí. Místo var uvnitř funkce se používají dva parametry: hodnota pro zobrazení a lambda-callback pro zpracování změn. Technicky to znamená, že podřízená komponenta se stává stateless (nemá vlastní stav) a nadřazená stateful (vlastní stav).

Příklad: komponenta TextField z Material3 neukládá zadaný text uvnitř sebe. Přijímá value: String a onValueChange: (String) -> Unit. Nadřazený, který volá TextField, deklaruje var value by remember { mutableStateOf("") } a předává value a onValueChange. Toto je klasické State Hoisting: TextField — jednoduchá komponenta (pouze zobrazuje a hlásí vstup), nadřazený — chytrý (vlastní stav).

Stateless vs Stateful: Stateless komponenta se testuje snadněji — nezávisí na vnitřním stavu, její chování je plně určeno vstupními parametry. Stateful komponenta je vhodná pro rychlé prototypování, ale hůře se znovu používá — je pevně vázána na jeden zdroj dat. State Hoisting dává možnost volby: libovolnou komponentu lze učinit stateless přesunutím stavu nahoru.

Jednosměrný tok dat (UDF) a State Hoisting

UDF (Unidirectional Data Flow) — je architektonický princip, při kterém se data pohybují jedním směrem: od zdroje pravdy (ViewModel nebo nadřazený Composable) k UI, a události opačným směrem. State Hoisting je implementace UDF na úrovni jednotlivých komponent. Místo toho, aby každá komponenta sama rozhodovala, kdy a jak změnit svůj stav, hlásí událost nadřazenému a nadřazený rozhoduje, jak stav změnit.

Výhody UDF: předvídatelnost — stav se mění pouze na jednom místě, což eliminuje race conditions; sledovatelnost — ze zásobníku volání lze rekonstruovat řetězec změn; testování — stateful logiku lze vyčlenit do samostatné třídy a testovat bez UI. Ve velkých projektech je UDF v kombinaci se State Hoisting de facto standardem.

Jediný zdroj pravdy (Single Source of Truth) — další princip doprovázející UDF. Každý fragment stavu má přesně jeden zdroj. Pokud dvě komponenty používají stejný stav, zdroj musí být společný (na úrovni ViewModel nebo společného nadřazeného). State Hoisting zaručuje, že zdroj je výše v hierarchii a nedochází k duplikaci stavu.

SměrCo se předáváJak je implementováno
Dolů (nadřazený → podřízený)Hodnota pro zobrazeníParametr value: T
Nahoru (podřízený → nadřazený)Událost změnyParametr onValueChange: (T) -> Unit

Pravidla State Hoisting: kdy a jak zvedat stav

Hlavní pravidlo: stav by měl být zvednut na nejnižší možnou úroveň dostatečnou pro všechny komponenty, které jej potřebují. Pokud je stav používán pouze uvnitř jedné komponenty — ponechte jej lokální. Pokud dvě sousední komponenty potřebují stejný stav — zvedněte jej do společného nadřazeného. Pokud je stav potřebný na celé obrazovce — zvedněte jej do ViewModel.

Pravidlo minimálního zvedání zabraňuje zbytečné složitosti. Nemá smysl zvedat stav textového pole do ViewModel, pokud je používán pouze uvnitř jedné obrazovky a není ukládán při opětovném vytvoření Activity. Použijte rememberSaveable na úrovni nadřazeného obrazovky, ne ViewModel, pro UI stav, který musí přežít otočení obrazovky, ale není potřebný pro obchodní logiku.

Kdy zvedat do ViewModel: pokud stav musí být zachován při opětovném vytvoření Activity, pokud je potřebný pro více obrazovek, pokud změna stavu spouští obchodní logiku (síťové požadavky, databáze). State Hoisting na úrovni ViewModel je typický vzor v architektuře MVVM, kde je UI vrstva stateless a ViewModel stateful.

kotlin
    // ❌ Špatně: komponenta vlastní svůj stav
@Composable
fun BadTextField(label: String) {
    var text by remember { mutableStateOf("") }
    TextField(value = text, onValueChange = { text = it }, label = { Text(label) })
}

    // ✅ Dobře: State Hoisting — stav v nadřazeném
@Composable
fun GoodTextField(value: String, onValueChange: (String) -> Unit, label: String) {
    TextField(value = value, onValueChange = onValueChange, label = { Text(label) })
}

    // Použití: nadřazený vlastní stav
@Composable
fun Form() {
    var name by rememberSaveable { mutableStateOf("") }
    GoodTextField(value = name, onValueChange = { name = it }, label = "Name")
}

Příklady State Hoisting v reálných komponentách

Zvažte přihlašovací obrazovku se dvěma poli (email, heslo) a tlačítkem. Všechny tři komponenty získávají stav prostřednictvím State Hoisting: email a heslo jsou spravovány nadřazeným, tlačítko získává status enabled jako hodnotu.

kotlin
    // State Hoisting na úrovni obrazovky
@Composable
fun LoginScreen(viewModel: LoginViewModel) {
    val uiState by viewModel.uiState.collectAsState()

    Column(modifier = Modifier.padding(16.dp)) {
        // Pole Email — State Hoisting přes lambdu
        EmailField(
            email = uiState.email,
            onEmailChange = { viewModel.onEmailChanged(it) }
        )

        // Pole hesla — podobně
        PasswordField(
            password = uiState.password,
            onPasswordChange = { viewModel.onPasswordChanged(it) }
        )

        // Tlačítko — dostává pouze enabled (read-only)
        LoginButton(enabled = uiState.isFormValid, onClick = viewModel::login)
    }
}

// Stateless komponenta: přijímá email + callback
@Composable
fun EmailField(email: String, onEmailChange: (String) -> Unit) {
    OutlinedTextField(
        value = email,
        onValueChange = onEmailChange,
        label = { Text("Email") },
        singleLine = true
    )
}

// Stateless komponenta tlačítka
@Composable
fun LoginButton(enabled: Boolean, onClick: () -> Unit) {
    Button(onClick = onClick, enabled = enabled) {
        Text("Přihlásit")
    }
}

EmailField a PasswordField — zcela stateless. Lze je znovu použít na libovolné obrazovce, připojené k libovolnému zdroji dat. LoginButton získává enabled jako read-only — to je další forma State Hoisting, kde stav není zvedán (tlačítko se nemůže samo aktivovat), ale je předáván hotový. Tento přístup poskytuje maximální flexibilitu s minimální provázaností komponent.

State Hoisting vs lokální stav: kritéria výběru

Ne každý stav je třeba zvedat. Lokální stav (State uvnitř Composable) je oprávněný, když: data jsou potřebná pouze uvnitř jedné komponenty, neovlivňují sousední prvky, nemusí přežít recompozici konkrétní sekce. Například stav animace, focus vstupního pole, aktuální pozice scrollování — je rozumné držet lokálně.

Kdy je State Hoisting nezbytný: stav je používán několika podřízenými komponentami; změna v jednom podřízeném se musí odrážet v druhém; je třeba testovat logiku změny stavu odděleně od UI; stav musí být zachován při opětovném vytvoření Activity. V těchto případech lokální stav vytváří duplikaci a nekonzistenci dat.

Hybridní přístup: držte minimální stav lokálně, zbytek zvedněte. Pravidlo Compose: „zvedejte stav tak vysoko, jak je to nutné, a tak nízko, jak je to možné. V praxi to znamená začít s lokálním remember, a teprve když se objeví potřeba přístupu z jiné komponenty — zvednout úroveň. Nedělejte State Hoisting preventivně — komplikuje to kód bez potřeby.

Často kladené otázky

Čím se liší State Hoisting od ViewModel?

State Hoisting — je vzor na úrovni UI komponent. ViewModel — je architektonická vrstva pro obchodní logiku. State Hoisting může zvedat stav na úroveň nadřazeného Composable, na úroveň obrazovky nebo do ViewModel. ViewModel — je nejvyšší bod zvedání pro stav, který musí přežít opětovné vytvoření Activity.

Jak testovat komponentu se State Hoisting?

Stateless komponenta se testuje jednoduchým předáním hodnot. Zavolejte Composable s potřebnými parametry a zkontrolujte zobrazení pomocí ComposeTestRule. Změna stavu se testuje na úrovni nadřazeného nebo ViewModel — odděleně od UI. To výrazně zjednodušuje testy: není třeba simulovat recompozici uvnitř komponenty.

Lze zvedat State pouze pro čtení?

Ano, to je běžná praxe. Pokud komponenta potřebuje pouze zobrazovat data bez možnosti je měnit — předejte State<T> (read-only). Komponenta bude přihlášena ke změnám, ale nebude je moci iniciovat. To posiluje zapouzdření a chrání data před nežádoucími mutacemi.

Co když je třeba zvednout stav o 3+ úrovně hloubky?

Pro hluboké předávání použijte CompositionLocal nebo předávání prostřednictvím parametrů nadřazeného Composable. Pokud je stav potřebný na celé obrazovce — přesuňte jej do ViewModel a použijte collectAsState(). Předávání přes 5+ úrovní je známkou špatné architektury; přehodnoťte hierarchii komponent.

Ovlivňuje State Hoisting výkon?

State Hoisting může mírně zvýšit počet recompozic, protože změna v nadřazeném může recomponovat všechny podřízené. Použijte derivedStateOf pro filtrování změn a keys v LazyColumn pro cílené aktualizace. Ve většině scénářů je režie State Hoisting zanedbatelná ve srovnání s výhodami udržovatelnosti.

Shrnutí

  • State Hoisting přesouvá stav do nadřazené komponenty, činí podřízenou stateless
  • UDF zaručuje jednosměrný tok dat: stav dolů, události nahoru
  • Znovupoužití — stateless komponenty lze připojit k libovolnému zdroji dat
  • Testování — UI testy kontrolují pouze zobrazení, logika se testuje odděleně
  • Minimální zvedání — zvedejte přesně tak, jak je třeba
  • ViewModel — nejvyšší bod zvedání pro stav s obchodní logikou
  • Doporučení: začněte s lokálním remember, zvedejte pouze při potřebě

Vyvineme mobilní aplikaci na klíč

IT Sectr vytváří aplikace pro iOS a Android pro startupy a podniky od roku 2017. Poradíme vám a navrhneme nejlepší řešení.

Prodiskutovat projekt

Přečtěte si také