State Hoisting, Jetpack Compose'da durumun bir alt Composable fonksiyonundan üst fonksiyona taşındığı ve alt fonksiyonun parametreler aracılığıyla veri alıp geri çağırmalar yoluyla değişiklikleri bildirdiği bir desendir. Bu, durumun yukarı çıktığı ve olayların aşağı indiği tek yönlü veri akışı (UDF) ilkesinin bir uygulamasıdır. Google Android Developers, 2026'ya göre State Hoisting, bileşenleri yeniden kullanılabilir, test edilebilir ve öngörülebilir hale getirir.
Önemli Noktalar
State Hoisting, bir Composable fonksiyonunun duruma sahip olmadığı, onu dışarıdan aldığı bir desendir. Fonksiyon içinde var kullanmak yerine iki parametre kullanılır: görüntülenecek bir değer ve değişiklikleri işlemek için bir lambda geri çağırması. Teknik olarak bu, alt bileşenin durumsuz (stateless) hale geldiği, üst bileşenin ise durumlu (stateful) olduğu anlamına gelir.
Örnek: Material3'teki TextField bileşeni girilen metni dahili olarak saklamaz. value: String ve onValueChange: (String) -> Unit'i kabul eder. TextField'ı çağıran üst, var value by remember { mutableStateOf("") } bildirir ve value ile onValueChange'i iletir. Bu klasik State Hoisting'dir: TextField basit bir bileşendir (sadece görüntüler ve girdiyi bildirir), üst ise akıllıdır (duruma sahiptir).
Stateless ve Stateful: Stateless bir bileşeni test etmek daha kolaydır — iç duruma bağlı değildir, davranışı tamamen girdi parametreleri tarafından belirlenir. Stateful bir bileşen hızlı prototipleme için uygundur ancak yeniden kullanımı daha zordur: tek bir veri kaynağına sıkıca bağlıdır. State Hoisting size seçenek sunar: durumu yukarı taşıyarak herhangi bir bileşen stateless hale getirilebilir.
UDF (Tek Yönlü Veri Akışı), verilerin tek bir yönde hareket ettiği bir mimari ilkedir: gerçeğin kaynağından (ViewModel veya üst Composable) UI'a ve olaylar ters yönde akar. State Hoisting, bireysel bileşen düzeyinde UDF'nin uygulanmasıdır. Her bileşenin kendi durumunu ne zaman ve nasıl değiştireceğine karar vermesi yerine, üst bileşene bir olay hakkında bilgi verir ve üst, durumun nasıl değiştirileceğine karar verir.
UDF'nin avantajları: öngörülebilirlik — durum yalnızca tek bir yerde değişir, yarış koşullarını ortadan kaldırır; izlenebilirlik — çağrı yığını, değişiklik zincirinin yeniden oluşturulmasına olanak tanır; test — durumlu mantık ayrı bir sınıfa çıkarılabilir ve UI olmadan test edilebilir. Büyük projelerde, State Hoisting ile birleştirilmiş UDF fiili standarttır.
Tek Gerçek Kaynağı (Single Source of Truth), UDF'ye eşlik eden başka bir ilkedir. Durumun her parçasının tam olarak bir kaynağı vardır. İki bileşen aynı durumu kullanıyorsa, kaynak paylaşılmalıdır (ViewModel veya ortak üst düzeyinde). State Hoisting, kaynağın hiyerarşide yukarıda olmasını ve durum tekrarının oluşmamasını sağlar.
| Yön | İletilen şey | Nasıl uygulanır |
|---|---|---|
| Aşağı (üst → alt) | Görüntülenecek değer | Parametre value: T |
| Yukarı (alt → üst) | Değişiklik olayı | Parametre onValueChange: (T) -> Unit |
Temel kural: durum, ona ihtiyaç duyan tüm bileşenler için yeterli olan mümkün olan en düşük seviyeye yükseltilmelidir. Durum yalnızca bir bileşen içinde kullanılıyorsa — yerel olarak tutun. İki bitişik bileşen aynı duruma ihtiyaç duyuyorsa — ortak üste yükseltin. Durum tüm ekranda gerekliyse — ViewModel'e yükseltin.
Minimum yükseltme kuralı gereksiz karmaşıklığı önler. Metin alanı durumunu, yalnızca bir ekran içinde kullanılıyorsa ve Activity yeniden oluşturulduğunda kalıcı değilse ViewModel'e yükseltmenin bir anlamı yoktur. Ekran döndürmesinden sonra kalıcı olması gereken ancak iş mantığı tarafından ihtiyaç duyulmayan UI durumu için ViewModel'de değil, ekran üst düzeyinde rememberSaveable kullanın.
ViewModel'e ne zaman yükseltilmeli: durum Activity yeniden oluşturulmasından sonra kalıcı olmalıysa, birden çok ekran tarafından ihtiyaç duyuluyorsa, durum değişikliği iş mantığını (ağ istekleri, veritabanı) tetikliyorsa. ViewModel düzeyinde State Hoisting, UI katmanının stateless ve ViewModel'in stateful olduğu MVVM mimarisinde standart bir desendir.
// ❌ Kötü: bileşen kendi durumuna sahip
@Composable
fun BadTextField(label: String) {
var text by remember { mutableStateOf("") }
TextField(value = text, onValueChange = { text = it }, label = { Text(label) })
}
// ✅ İyi: State Hoisting — durum üstte
@Composable
fun GoodTextField(value: String, onValueChange: (String) -> Unit, label: String) {
TextField(value = value, onValueChange = onValueChange, label = { Text(label) })
}
// Kullanım: üst duruma sahip
@Composable
fun Form() {
var name by rememberSaveable { mutableStateOf("") }
GoodTextField(value = name, onValueChange = { name = it }, label = "Name")
}
İki alan (e-posta, şifre) ve bir buton içeren bir giriş ekranı düşünün. Her üç bileşen de State Hoisting aracılığıyla durumu alır: e-posta ve şifre üst tarafından yönetilir, buton etkin durumunu bir değer olarak alır.
// Ekran düzeyinde State Hoisting
@Composable
fun LoginScreen(viewModel: LoginViewModel) {
val uiState by viewModel.uiState.collectAsState()
Column(modifier = Modifier.padding(16.dp)) {
// E-posta alanı — lambda ile State Hoisting
EmailField(
email = uiState.email,
onEmailChange = { viewModel.onEmailChanged(it) }
)
// Şifre alanı — benzer şekilde
PasswordField(
password = uiState.password,
onPasswordChange = { viewModel.onPasswordChanged(it) }
)
// Buton — yalnızca enabled alır (salt okunur)
LoginButton(enabled = uiState.isFormValid, onClick = viewModel::login)
}
}
// Stateless bileşen: e-posta + geri çağırma alır
@Composable
fun EmailField(email: String, onEmailChange: (String) -> Unit) {
OutlinedTextField(
value = email,
onValueChange = onEmailChange,
label = { Text("E-posta") },
singleLine = true
)
}
// Stateless buton bileşeni
@Composable
fun LoginButton(enabled: Boolean, onClick: () -> Unit) {
Button(onClick = onClick, enabled = enabled) {
Text("Giriş")
}
}
EmailField ve PasswordField tamamen durumsuzdur. Herhangi bir veri kaynağına bağlanarak herhangi bir ekranda yeniden kullanılabilirler. LoginButton, enabled'i salt okunur olarak alır — bu, durumun yükseltilmediği (buton kendini etkinleştiremez) ancak hazır olarak aşağı iletildiği başka bir State Hoisting biçimidir. Bu yaklaşım, minimum bileşen bağımlılığı ile maksimum esneklik sağlar.
Her durumun yükseltilmesi gerekmez. Yerel durum (Composable içindeki State) şu durumlarda haklı çıkar: veriler yalnızca bir bileşen içinde gereklidir, kardeş öğeleri etkilemez ve belirli bir bölümün yeniden oluşturulmasından sonra kalıcı olması gerekmez. Örneğin, animasyon durumu, giriş alanı odağı, geçerli kaydırma konumu — bunları yerel olarak tutmak mantıklıdır.
State Hoisting ne zaman gereklidir: durum birden çok alt bileşen tarafından kullanılır; bir alt bileşendeki değişiklik diğerine yansıtılmalıdır; durum değişikliklerinin mantığı UI'dan ayrı olarak test edilmelidir; durum Activity yeniden oluşturulmasından sonra kalıcı olmalıdır. Bu durumlarda, yerel durum veri tekrarı ve tutarsızlığı yaratır.
Hibrit yaklaşım: minimum durumu yerel olarak tutun, geri kalanını yükseltin. Compose kuralı: “durumu gerektiği kadar yükseğe ve mümkün olduğunca aşağıya yükseltin.” Pratikte bu, yerel remember ile başlamak ve yalnızca başka bir bileşenden erişim gerektiğinde seviyeyi yükseltmek anlamına gelir. State Hoisting'i önleyici olarak uygulamayın — kodu gereksiz yere karmaşık hale getirir.
Sıkça Sorulan Sorular
State Hoisting bir UI bileşen düzeyi desenidir. ViewModel, iş mantığı için bir mimari katmandır. State Hoisting, durumu üst Composable düzeyine, ekran düzeyine veya ViewModel'e yükseltebilir. ViewModel, Activity yeniden oluşturulmasından sonra kalıcı olması gereken durum için en yüksek yükseltme noktasıdır.
Stateless bir bileşen, basitçe değerler iletilerek test edilir. Gerekli parametrelerle Composable'ı çağırın ve ComposeTestRule ile görüntülemeyi kontrol edin. Durum değişiklikleri, üst veya ViewModel düzeyinde test edilir — UI'dan ayrı olarak. Bu, testleri önemli ölçüde basitleştirir: bileşen içinde yeniden oluşturmayı simüle etmeye gerek yoktur.
Evet, bu yaygın bir uygulamadır. Bir bileşenin yalnızca verileri değiştirme yeteneği olmadan görüntülemesi gerekiyorsa — State<T> (salt okunur) iletin. Bileşen değişikliklere abone olur ancak bunları başlatamaz. Bu, kapsüllemeyi güçlendirir ve verileri istenmeyen mutasyonlardan korur.
Derin iletim için CompositionLocal kullanın veya üst Composable parametreleri aracılığıyla iletin. Durum tüm ekranda gerekliyse — bir ViewModel'e çıkarın ve collectAsState() kullanın. 5+ seviye üzerinden iletim, yanlış mimarinin bir işaretidir; bileşen hiyerarşisini yeniden değerlendirin.
State Hoisting, üstteki bir değişiklik tüm alt öğeleri yeniden oluşturabileceğinden yeniden oluşturma sayısını biraz artırabilir. Değişiklikleri filtrelemek için derivedStateOf ve hedefli güncellemeler için LazyColumn'da keys kullanın. Çoğu senaryoda, State Hoisting'in ek yükü, bakım kolaylığı avantajına kıyasla ihmal edilebilir düzeydedir.
Özet
Anahtar teslim bir mobil uygulama geliştireceğiz
IT Sectr, 2017'den beri girişimler ve işletmeler için iOS ve Android uygulamaları oluşturmaktadır. Size danışmanlık yapacak ve en iyi çözümü önereceğiz.
Ayrıca okuyun