State Hoisting — bu Jetpack Compose-da bir nümunədir ki, burada vəziyyət uşaq Composable funksiyasından valideyn funksiyasına çıxarılır, uşaq isə məlumatları parametrlər vasitəsilə alır və dəyişikliklər barədə callback-lər vasitəsilə xəbər verir. Bu, vəziyyətin yuxarı qaldırıldığı və hadisələrin aşağı endiyi birtərəfli məlumat axını (UDF) prinsipinin tətbiqidir. Google Android Developers, 2026-ya görə, State Hoisting komponentləri təkrar istifadə oluna bilən, test edilə bilən və proqnozlaşdırıla bilən edir.
Əsas məqamlar
State Hoisting (vəziyyətin qaldırılması) — bu nümunədir ki, Composable funksiyası vəziyyətə sahib olmur, onu xaricdən alır. Funksiya daxilində var əvəzinə iki parametr istifadə olunur: göstərmək üçün dəyər və dəyişiklikləri idarə etmək üçün lambda-callback. Texniki olaraq bu, uşaq komponentin stateless (öz vəziyyəti yoxdur), valideynin isə stateful (vəziyyətə sahibdir) olması deməkdir.
Nümunə: Material3-dən TextField komponenti daxil edilmiş mətni özündə saxlamır. O, value: String və onValueChange: (String) -> Unit qəbul edir. TextField-i çağıran valideyn var value by remember { mutableStateOf("") } elan edir və value ilə onValueChange-i ötürür. Bu klassik State Hoisting-dir: TextField — sadə komponent (sadəcə göstərir və daxiletmə barədə xəbər verir), valideyn — ağıllı (vəziyyətə sahibdir).
Stateless vs Stateful: Stateless komponenti test etmək asandır — o, daxili vəziyyətdən asılı deyil, onun davranışı tamamilə giriş parametrləri ilə müyyən edilir. Stateful komponent sürətli prototipləşdirmə üçün rahatdır, lakin təkrar istifadəsi çətindir — o, bir məlumat mənbəyinə sıx bağlıdır. State Hoisting seçim verir: hər bir komponent vəziyyəti yuxarı çıxararaq stateless edilə bilər.
UDF (Unidirectional Data Flow) — bu memarlıq prinsipidir ki, burada məlumatlar bir istiqamətdə hərəkət edir: həqiqət mənbəyindən (ViewModel və ya valideyn Composable) UI-ya, hadisələr isə əks istiqamətdə. State Hoisting ayrı-ayrı komponentlər səviyyəsində UDF-in tətbiqidir. Hər bir komponentin öz vəziyyətini nə vaxt və necə dəyişdirəcəyinə özü qərar verməsi əvəzinə, o, valideynə hadisə barədə məlumat verir, valideyn isə vəziyyəti necə dəyişdirməyə qərar verir.
UDF-in üstünlükləri: proqnozlaşdırıla bilmə — vəziyyət yalnız bir yerdə dəyişir, bu da race condition-ları aradan qaldırır; traceability — çağırış izi ilə dəyişiklik zənciri bərpa oluna bilər; test etmə — stateful məntiqi ayrı sinfə çıxarıb UI olmadan test etmək olar. Böyük layihələrdə UDF-in State Hoisting ilə birləşməsi de-fakto standartdır.
Vahid həqiqət mənbəyi (Single Source of Truth) — UDF-ə müşayiət edən digər prinsip. Vəziyyətin hər bir hissəsinin dəqiq bir mənbəyi var. Əgər iki komponent eyni vəziyyətdən istifadə edirsə, mənbə ortaq olmalıdır (ViewModel və ya ortaq valideyn səviyyəsində). State Hoisting mənbəyin iyerarxiyada daha yuxarıda olmasını və vəziyyətin təkrarlanmamasını təmin edir.
| İstiqamət | Nə ötürülür | Necə tətbiq olunur |
|---|---|---|
| Aşağı (valideyn → uşaq) | Göstəriləcək dəyər | Parametr value: T |
| Yuxarı (uşaq → valideyn) | Dəyişiklik hadisəsi | Parametr onValueChange: (T) -> Unit |
Əsas qayda: vəziyyət ona ehtiyacı olan bütün komponentlər üçün kifayət edən minimal səviyyəyə qaldırılmalıdır. Əgər vəziyyət yalnız bir komponent daxilində istifadə olunursa — onu lokal saxlayın. Əgər iki qonşu komponent eyni vəziyyətə ehtiyac duyursa — ortaq valideynə qaldırın. Əgər vəziyyət bütün ekran üçün lazımdırsa — ViewModel-ə qaldırın.
Minimal qaldırma qaydası lazımsız mürəkkəbliyin qarşısını alır. Mətn sahəsinin vəziyyətini ViewModel-ə qaldırmağın mənası yoxdur, əgər o, yalnız bir ekran daxilində istifadə olunur və Activity yenidən yaradılanda saxlanmırsa. Ekranın fırlanmasından sağ çıxmalı, lakin biznes məntiqinə ehtiyacı olmayan UI vəziyyəti üçün ViewModel əvəzinə ekran valideyni səviyyəsində rememberSaveable istifadə edin.
Nə vaxt ViewModel-ə qaldırmalı: əgər vəziyyət Activity yenidən yaradılanda saxlanmalıdırsa, bir neçə ekrana lazımdırsa, vəziyyət dəyişikliyi biznes məntiqini (şəbəkə sorğuları, verilənlər bazası) işə salırsa. ViewModel səviyyəsində State Hoisting MVVM memarlığında tipik nümunədir, burada UI təbəqəsi stateless, ViewModel isə stateful-dir.
// ❌ Pis: komponent öz vəziyyətinə sahibdir
@Composable
fun BadTextField(label: String) {
var text by remember { mutableStateOf("") }
TextField(value = text, onValueChange = { text = it }, label = { Text(label) })
}
// ✅ Yaxşı: State Hoisting — vəziyyət valideyndə
@Composable
fun GoodTextField(value: String, onValueChange: (String) -> Unit, label: String) {
TextField(value = value, onValueChange = onValueChange, label = { Text(label) })
}
// İstifadə: valideyn vəziyyətə sahibdir
@Composable
fun Form() {
var name by rememberSaveable { mutableStateOf("") }
GoodTextField(value = name, onValueChange = { name = it }, label = "Name")
}
Giriş ekranını nəzərdən keçirək, burada iki sahə (email, şifrə) və düymə var. Hər üç komponent vəziyyəti State Hoisting vasitəsilə alır: email və şifrə valideyn tərəfindən idarə olunur, düymə enabled statusunu dəyər kimi alır.
// State Hoisting ekran səviyyəsində
@Composable
fun LoginScreen(viewModel: LoginViewModel) {
val uiState by viewModel.uiState.collectAsState()
Column(modifier = Modifier.padding(16.dp)) {
// Email sahəsi — State Hoisting lambda vasitəsilə
EmailField(
email = uiState.email,
onEmailChange = { viewModel.onEmailChanged(it) }
)
// Şifrə sahəsi — eyni şəkildə
PasswordField(
password = uiState.password,
onPasswordChange = { viewModel.onPasswordChanged(it) }
)
// Düymə — yalnız enabled alır (yalnız oxumaq üçün)
LoginButton(enabled = uiState.isFormValid, onClick = viewModel::login)
}
}
// Stateless komponent: email + callback alır
@Composable
fun EmailField(email: String, onEmailChange: (String) -> Unit) {
OutlinedTextField(
value = email,
onValueChange = onEmailChange,
label = { Text("Email") },
singleLine = true
)
}
// Stateless düymə komponenti
@Composable
fun LoginButton(enabled: Boolean, onClick: () -> Unit) {
Button(onClick = onClick, enabled = enabled) {
Text("Daxil ol")
}
}
EmailField və PasswordField — tamamilə stateless. Onları istənilən ekranda, istənilən məlumat mənbəyinə qoşaraq təkrar istifadə etmək olar. LoginButton enabled-i read-only kimi alır — bu, vəziyyətin qaldırılmadığı (düymə özünü aktivləşdirə bilməz), hazır şəkildɘ ötürüldüyü başqa bir State Hoisting formasıdır. Bu yanaşma minimal komponent bağlılığı ilə maksimum çeviklik verir.
Hər vəziyyəti qaldırmaq lazım deyil. Lokal vəziyyət (Composable daxilində State) haqlıdır, o zaman: məlumatlar yalnız bir komponent daxilində lazımdır, qonşu elementlərə təsir etmir, müəyyən bölmənin rekompozisiyasından sağ çıxmalı deyil. Məsələn, animasiya vəziyyəti, daxiletmə sahəsinin focus-u, cari scroll mövqeyi — lokal saxlamaq məqsədəuyğundur.
State Hoisting nə vaxt zəruridir: vəziyyət bir neçə uşaq komponent tərəfindən istifadə olunur; bir uşaqdakı dəyişiklik digərində əks olunmalıdır; vəziyyət dəyişikliyi məntiqini UI-dan ayrı test etmək lazımdır; vəziyyət Activity yenidən yaradılanda saxlanmalıdır. Bu hallarda lokal vəziyyət məlumatların təkrarlanmasına və uyğunsuzluğuna səbəb olur.
Hibrid yanaşma: minimal vəziyyəti lokal saxlayın, qalanını qaldırın. Compose qaydası: “vəziyyəti lazım olduğu qədər yüksək, mümkün olduğu qədər aşağı qaldırın”. Praktikada bu, lokal remember ilə başlamaq və yalnız başqa komponentdən giriş ehtiyacı yarandıqda səviyyəni qaldırmaq deməkdir. State Hoisting-i profilaktik tətbiq etməyin — bu, kodu lazımsız yerə çətinləşdirir.
Tez-tez verilən suallar
State Hoisting — bu UI komponentləri səviyyəsində nümunədir. ViewModel — biznes məntiqi üçün memarlıq qatıdır. State Hoisting vəziyyəti valideyn Composable səviyyəsinə, ekran səviyyəsinə və ya ViewModel-ə qaldıra bilər. ViewModel — Activity-nin yenidən yaradılmasından sağ çıxmalı olan vəziyyət üçün ən yüksək qaldırma nöqtəsidir.
Stateless komponent sadəcə dəyərləri ötürməklə test edilir. Lazımi parametrlərlə Composable-i çağırın və ComposeTestRule vasitəsilə göstərilməni yoxlayın. Vəziyyət dəyişikliyi valideyn və ya ViewModel səviyyəsində — UI-dan ayrı şəkildə test edilir. Bu, testləri çox asanlaşdırır: komponent daxilində rekompozisiyanı simulyasiya etməyə ehtiyac yoxdur.
Bəli, bu geniş yayılmış təcrübədir. Əgər komponent yalnız məlumatı dəyişdirmədən göstərməlidirsə — State<T> (ötürün). Komponent dəyişikliklərə abunə olacaq, lakin onları başlada bilməyəcək. Bu, inkapsulyasiyanı gücləndirir və məlumatları arzuolunmaz mutasiyalardan qoruyur.
Dərin ötürmə üçün CompositionLocal və ya valideyn Composable parametrləri vasitəsilə ötürmə istifadə edin. Əgər vəziyyət bütün ekran üçün lazımdırsa — onu ViewModel-ə çıxarın və collectAsState() istifadə edin. 5+ səviyyədən ötürmək — səhv memarlıq əlamətidir; komponent iyerarxiyasını yenidən nəzərdən keçirin.
State Hoisting rekompozisiyaların sayını bir qədər artıra bilər, çünki valideyndəki dəyişiklik bütün uşaqları yenidən kompozisiya edə bilər. Dəyişiklikləri filtrləmək üçün derivedStateOf və LazyColumn-də nöqtəvi yeniləmələr üçün keys istifadə edin. Əksər ssenarilərdə State Hoisting-in yükü, saxlanıla bilirlik faydası ilə müqayisədə əhəmiyyətsiz dərəcədə azdır.
Nəticə
Açar təslim mobil tətbiq hazırlayacağıq
IT Sectr 2017-ci ildən startaplar və bizneslər üçün iOS və Android tətbiqləri yaradır. Sizə məsləhət verəcəyik və ən yaxşı həlli təklif edəcəyik.
Həm də oxuyun