---
title: 'Durum Kaldırma'
source: 'https://academia.sh/tr/kurslar/compose/durum-kaldirma'
course: 'Jetpack Compose ile Arayüz'
language: tr
updated: '2026-10-21T05:02:38+00:00'
license: 'CC BY-SA 4.0'
objectives:
    - 'Durumsuz bir bileşen işlevinin değeri parametreyle, değişiklik isteğini geri çağrıyla aldığını açıklar'
    - 'Okuyucuların ortak atasını durumun sahibi olarak bulur'
    - 'Sahibe giden olayın yukarı, sahibinden inen değerin aşağı gittiğini ölçer'
    - 'Durum gereğinden yükseğe kaldırıldığında hareket sayısının arttığını, yönün değişmediğini gösterir'
---

# Durum Kaldırma

Durum kaldırma, durumu onu okuyan ve yazan bileşen işlevlerinin ortak atasına taşır; değer aşağı iner, olay yukarı çıkar. Ders sahibe giden olayın yönünü ve sahibin yüksekliğinin hareket sayısını nasıl değiştirdiğini ölçer.

Önceki derste `Screen` bir adedi hatırladı ve iki çocuğu değeri okudu. Değer aşağı indi, ama okuyucu o değeri değiştirmek istediğinde yapabileceği bir şey yoktu: durum onun değil, atasına aitti. Bu derste okuyucunun isteği sahibine döner. Durumu okuyan ve yazan bileşen işlevlerinin ortak atasına taşımaya durum kaldırma denir. Dersin sorusu önceki derslerle aynıdır: **bu veri arayüz ağacında hangi yöne gidiyor?**

```kotlin
// Direction.kt — bir verinin arayuz agacinda hangi yone gittigini siniflandirir
class Tree(private val parentOf: Map<String, String>) {
    fun contains(node: String): Boolean = node in parentOf.keys || node in parentOf.values
    fun parent(node: String): String? = parentOf[node]
    fun ancestors(node: String): List<String> {
        val chain = mutableListOf<String>()
        var current = parentOf[node]
        while (current != null) {
            chain.add(current)
            current = parentOf[current]
        }
        return chain
    }
}

class Move(val label: String, val from: String, val to: String, tree: Tree) {
    val direction: String = when {
        !tree.contains(from) || !tree.contains(to) -> "dis"
        to in tree.ancestors(from) -> "yukari"
        tree.parent(to) == from -> "asagi"
        from in tree.ancestors(to) -> "derin"
        else -> error("akrabasiz: $from ve $to")
    }

    fun describe() {
        println("$label: kimden=$from | kime=$to -> $direction")
    }
}

fun countDirections(moves: List<Move>) {
    for (name in listOf("asagi", "yukari", "derin", "dis")) {
        println("$name: ${moves.count { it.direction == name }}")
    }
}
```

## Değer Aşağı, Olay Yukarı

Platform belgesi durumu, onu okuyan ve yazan bileşen işlevlerinin en alt ortak atasına kaldırmayı önerir. Durumun sahibi tüketicilere değiştirilemez durumu ve onu değiştirecek olayları sunar. Bileşen işlevi bunu iki parametreyle alır: gösterilecek `value` ve değişiklik istendiğinde çağrılacak `onValueChange`. Durumu kendi tutmayan işleve durumsuz denir; durumu tutup bir durumsuz işleve veren işleve durumlu.

```kotlin
// Platform kodu: QuantityScreen
import androidx.compose.runtime.*

@Composable
fun QuantityField(value: Int, onValueChange: (Int) -> Unit) {
    Button(onClick = { onValueChange(value + 1) }) {
        Text("Adet: $value")
    }
}

@Composable
fun QuantityScreen() {
    var quantity by remember { mutableStateOf(1) }
    QuantityField(value = quantity, onValueChange = { quantity = it })
}
```

`QuantityField` durumu tutmaz. Değeri parametreyle alır, dokunuşu geri çağrıyla bildirir; yeni değeri yazmak `QuantityScreen`'in işidir. Değer ebeveynden çocuğa, olay çocuktan ebeveynine gider. Buna tek yönlü veri akışı denir: her hareket tek yönlüdür, ama iki hareket zıt yönlere gider. Bu parça platform kodudur ve burada çıktı, düzen ya da süre iddia etmiyoruz. Model, platformun bu kuralını kurar; model platformun kendisi değildir.

Bu ayrım M12/K03'ten farklıdır. O kursun "bu sonucu kim değiştirebiliyor" sorusu sonucun sahibini sınıflar. Bu derste sahibi bir model işlevi bulur, ama ölçü sahip değildir: ölçü, sahibe giden ve sahibinden çıkan hareketin yönüdür.

## Ortak Ata Sahip Olur

Model, okuyucuların en alt ortak atasını bulan bir işlevle başlar. Ad bu derste yenidir; açılış dersindeki `hoistTo` ile aynı işi yapar.

```kotlin
// Owner.kt — okuyucularin en alt ortak atasi durumun sahibidir
fun commonOwner(readers: List<String>, tree: Tree): String {
    val paths = readers.map { listOf(it) + tree.ancestors(it) }
    return paths.first().first { node -> paths.all { node in it } }
}
```

Sepet ekranında adedi `CartList` değiştirir ve `CheckoutButton` toplamı göstermek için okur. Bunlar kardeştir. Önceki dersten biliyoruz ki kardeşler arasında doğrudan hareket kurulamaz; ikisinin paylaştığı değer ortak atadan geçer. Bir yardımcı bu bölünmeyi kurar: kaynaktan ortak sahibe bir yukarı hareket, sahibinden hedefe bir aşağı hareket.

```kotlin
// Siblings.kt — kardesler arasi istegi ortak ata uzerinden iki harekete boler
fun viaOwner(label: String, from: String, to: String, tree: Tree): List<Move> {
    val owner = commonOwner(listOf(from, to), tree)
    return listOf(
        Move("$label-yukari", from, owner, tree),
        Move("$label-asagi", owner, to, tree),
    )
}
```

```kotlin
// Main.kt — kardesten kardese hareket iki harekettir
fun main() {
    val tree = Tree(mapOf(
        "Screen" to "App",
        "Header" to "Screen",
        "CartList" to "Screen",
        "CartRow" to "CartList",
        "CheckoutButton" to "Screen",
    ))
    println("durum sahibi: ${commonOwner(listOf("CartList", "CheckoutButton"), tree)}")
    val moves = viaOwner("adet", "CartList", "CheckoutButton", tree)
    moves.forEach { it.describe() }
    countDirections(moves)
}
```

```text
durum sahibi: Screen
adet-yukari: kimden=CartList | kime=Screen -> yukari
adet-asagi: kimden=Screen | kime=CheckoutButton -> asagi
asagi: 1
yukari: 1
derin: 0
dis: 0
```

Sahip `Screen` çıktı. `CartList`'ten `CheckoutButton`'a giden istek önce sahibe çıktı: yukarı. Sahipten düğmeye indi: aşağı. Bu dersin yönü olan yukarı, kardeşler arası her paylaşımın ilk yarısıdır.

**BI5.** Model sahibi yalnız okuyucuların ve yazanın düğüm adlarından bulur. Platformda sahibin yazma ve okuma mantığının arayüz mantığı mı iş mantığı mı olduğuna göre ağacın dışında, örneğin bir `ViewModel`'de de durabilmesi modelde yoktur.

## Tam Akış

Şimdi tüm akışı kuralım. Sahip `commonOwner` ile seçilir. Her okuyucuya sahibinden değer iner, yazan düğümden sahibe olay çıkar. Değer ve olay aradaki her düzeyden parametre ve geri çağrıyla geçer; bir düzey atlanmaz. Bunu yapan yardımcı bir aşağı yolu çıkarır.

```kotlin
// Flow.kt — sahipten okuyuculara inen degerler, yazandan sahibe cikan olay
fun downPath(owner: String, node: String, tree: Tree): List<String> =
    ((listOf(node) + tree.ancestors(node)).takeWhile { it != owner } + owner).reversed()

fun flowMoves(owner: String, readers: List<String>, writer: String, tree: Tree): List<Move> {
    val values = readers
        .flatMap { reader -> downPath(owner, reader, tree).zipWithNext() }
        .distinct()
        .map { (from, to) -> Move("deger-${to.lowercase()}", from, to, tree) }
    val events = downPath(owner, writer, tree).reversed().zipWithNext()
        .map { (from, to) -> Move("olay-${from.lowercase()}", from, to, tree) }
    return values + events
}

fun liftTo(node: String, levels: Int, tree: Tree): String = tree.ancestors(node)[levels - 1]
```

`flowMoves` aynı hareketi iki okuyucu için iki kez saymaz; `distinct` ortak yol parçasını tek hareket yapar. `liftTo` bir düğümün birkaç düzey üstünü verir ve bir sonraki bölümde kullanılacak.

```kotlin
// Main.kt — deger asagi, olay yukari
fun main() {
    val tree = Tree(mapOf(
        "Screen" to "App",
        "Header" to "Screen",
        "CartList" to "Screen",
        "CartRow" to "CartList",
        "CheckoutButton" to "Screen",
    ))
    val readers = listOf("CartList", "CheckoutButton")
    val owner = commonOwner(readers, tree)
    println("durum sahibi: $owner")
    val moves = flowMoves(owner, readers, "CartList", tree)
    moves.forEach { it.describe() }
    countDirections(moves)
}
```

```text
durum sahibi: Screen
deger-cartlist: kimden=Screen | kime=CartList -> asagi
deger-checkoutbutton: kimden=Screen | kime=CheckoutButton -> asagi
olay-cartlist: kimden=CartList | kime=Screen -> yukari
asagi: 2
yukari: 1
derin: 0
dis: 0
```

İki değer sahibinden çocuklarına iner: iki aşağı. Adedi değiştiren dokunuş `CartList`'ten sahibe çıkar: bir yukarı. Sayı olarak aşağı önde, ama durum kaldırmanın yeni getirdiği hareket olaydır: durum yerelken olay yoktu, sahibe taşınınca yukarı gidecek bir istek doğdu. Dersin yönü bu yüzden yukarıdır.

Durum yalnız bir bileşen işlevine aitse kaldırılacak bir şey yoktur. Okuyucu da yazan da `CartList` ise ortak ata `CartList`'in kendisidir ve hareket kurulmaz.

```kotlin
// Main.kt — tek okuyucu: sahip okuyucunun kendisi
fun main() {
    val tree = Tree(mapOf(
        "Screen" to "App",
        "CartList" to "Screen",
        "CheckoutButton" to "Screen",
    ))
    val owner = commonOwner(listOf("CartList"), tree)
    println("durum sahibi: $owner")
    countDirections(flowMoves(owner, listOf("CartList"), "CartList", tree))
}
```

```text
durum sahibi: CartList
asagi: 0
yukari: 0
derin: 0
dis: 0
```

Kaldırma, yalnız paylaşım olduğunda gerekir. Yerel durum önceki dersteki gibi hareket üretmez.

## Sınırlayıcı Ölçüm

Durumu gerekenden yükseğe, `App`'e kaldırırsak ne değişir? Olay hâlâ sahibe gider; yönü yukarıdır. Ama sahip uzaklaştığı için değer ve olay aradaki her düzeyden geçmek zorunda kalır.

```kotlin
// Main.kt — ayni durum bir ust duzeye kaldirilinca hareket sayisi artar
fun main() {
    val tree = Tree(mapOf(
        "Screen" to "App",
        "Header" to "Screen",
        "CartList" to "Screen",
        "CartRow" to "CartList",
        "CheckoutButton" to "Screen",
    ))
    val readers = listOf("CartList", "CheckoutButton")
    val needed = commonOwner(readers, tree)
    for (owner in listOf(needed, liftTo(needed, 1, tree))) {
        println("durum sahibi: $owner")
        val moves = flowMoves(owner, readers, "CartList", tree)
        countDirections(moves)
        println("toplam: ${moves.size}")
    }
}
```

```text
durum sahibi: Screen
asagi: 2
yukari: 1
derin: 0
dis: 0
toplam: 3
durum sahibi: App
asagi: 3
yukari: 2
derin: 0
dis: 0
toplam: 5
```

Sahip `App` olunca değer `Screen`'e, oradan iki okuyucuya iner: üç aşağı hareket. Olay `CartList`'ten `Screen`'e, oradan `App`'e çıkar: iki yukarı hareket. Toplam üçten beşe çıktı. Dört kategori adı değişmedi; `derin` ve `dis` yine sıfır. `Screen` yalnız iletici oldu: değeri kullanmıyor, ama imzasında taşıyor. Platform belgesinin öğüdü de budur: durumu en alt ortak atasına kaldır ve gerekmeyen bileşen işlevlerine geçirme.

Kardeşler arası hareketin ortak ata üzerinden iki harekete bölünmesi ve sahibin yüksekliğinin hareket sayısını değiştirmesi aynı kurala bağlıdır: kural yalnız iki ucun ağaçtaki konumuna bakar. Hangi yolu seçtiğimizi ders söyler, kural değil.

**BI6.** Model, iletici düğümlerin değeri ve olayı olduğu gibi aktardığını varsayar. Platformda aradaki bileşen işlevinin değeri dönüştürmesi ya da olayı kendisinin işlemesi modelde yoktur.

## Özet

- Bu dersin yönü: yukarı. Durum kaldırılınca okuyucudan sahibine yeni bir hareket doğar: değişiklik isteği.
- Sahip, okuyucuların en alt ortak atasıdır: `CartList` ve `CheckoutButton` için `Screen`.
- Kardeşler arası istek iki harekete bölünür: yukarı 1, aşağı 1.
- Tam akışta iki değer aşağı iner, bir olay yukarı çıkar: aşağı 2, yukarı 1.
- Durum `App`'e kaldırılınca aşağı 3, yukarı 2 olur; toplam hareket 3'ten 5'e çıkar, kategoriler aynı kalır.

## Sonraki Adım

Bu derste olay sahibine döndü ve sahip değeri yeniden indirdi. Değer değişince hangi bileşen işlevlerinin yeniden çalışacağı ayrı bir sorudur. Sıradaki ders, `Yeniden Oluşturma`, değişikliğin sahibinden hangi düğümlere ulaştığını ve değerin okunmasının ertelenmesinin yönü nasıl değiştirdiğini ölçer.
