---
title: 'Durum Yönetimi'
source: 'https://academia.sh/tr/kurslar/react-native/durum-yonetimi'
course: 'React Native'
language: tr
updated: '2026-10-21T05:02:54+00:00'
license: 'CC BY-SA 4.0'
objectives:
    - 'Yerel durumu, paylaşılan durumu, durumun yukarı taşınmasını ve sağlayıcıyı birbirinden ayırır'
    - 'Yerel durum değişikliğinin yalnız sahibi olan düğümü güncellediğini ölçer'
    - 'Paylaşılan durumun bir değişikliği birden çok düğüme taşıdığını ve komut sayısını artırdığını gösterir'
    - 'Durum değişse bile görünen özellik değişmediyse hiçbir düğümün güncellenmediğini gösterir'
---

# Durum Yönetimi

Durum yönetimi, ekranın zamanla değişen verisinin nerede tutulacağını belirler: tek bileşende yerel ya da birçok ekranın okuduğu paylaşılan. Ders tek bir durum değişikliğinin sepet rozetini güncellediğini, ürün listesini korunan bıraktığını ölçer.

Gezinme ekranların ağaçta ne zaman kurulup söküldüğünü belirledi. Ekranın içindeki veri ise zamanla değişir: sepetteki ürün sayısı, bir giriş alanındaki metin, bir bölümün açık ya da kapalı olması. Bu verinin adı durumdur ve durum yönetimi, durumun nerede tutulacağına ve kimin okuyacağına karar vermektir.

Kursun sorusu değişmez: **bu güncelleme görünüm ağacındaki düğüme ne yapıyor?** Akıbet korunan, güncellenen, kurulan ya da sökülendir; güncellenen, kurulan ve sökülen düğümlerin toplamı komuttur. Akıbeti elle atamayız, kural verir:

```javascript
// fate.mjs — bir guncellemenin gorunum agacindaki her dugume ne yaptigini siniflandirir
export const FATES = ["korunan", "guncellenen", "kurulan", "sokulen"];

export function el(type, props = {}, children = [], key = null) {
  return { type, props, children, key };
}

function segment(node) {
  return node.key === null ? node.type : `${node.type}[${node.key}]`;
}

function identity(node, index) {
  return node.key === null ? `#${index}` : `key:${node.key}`;
}

function sameProps(a, b) {
  const names = [...new Set([...Object.keys(a), ...Object.keys(b)])].sort();
  return names.every((n) => JSON.stringify(a[n]) === JSON.stringify(b[n]));
}

function whole(node, path, fate, ops) {
  const here = `${path}/${segment(node)}`;
  ops.push({ fate, path: here });
  node.children.forEach((child) => whole(child, here, fate, ops));
}

export function reconcile(prev, next, path = "", ops = []) {
  if (prev === null) {
    whole(next, path, "kurulan", ops);
    return ops;
  }
  if (next === null) {
    whole(prev, path, "sokulen", ops);
    return ops;
  }
  if (prev.type !== next.type || prev.key !== next.key) {
    whole(prev, path, "sokulen", ops);
    whole(next, path, "kurulan", ops);
    return ops;
  }
  const here = `${path}/${segment(next)}`;
  ops.push({ fate: sameProps(prev.props, next.props) ? "korunan" : "guncellenen", path: here });
  const before = new Map(prev.children.map((child, i) => [identity(child, i), child]));
  const matched = new Set();
  next.children.forEach((child, i) => {
    const id = identity(child, i);
    matched.add(id);
    reconcile(before.has(id) ? before.get(id) : null, child, here, ops);
  });
  prev.children.forEach((child, i) => {
    if (!matched.has(identity(child, i))) reconcile(child, null, here, ops);
  });
  return ops;
}

export function printOps(ops) {
  ops.forEach((op) => console.log(`${op.fate}: ${op.path}`));
}

export function countFates(ops) {
  for (const name of FATES) {
    console.log(`${name}: ${ops.filter((op) => op.fate === name).length}`);
  }
  console.log(`komut: ${ops.filter((op) => op.fate !== "korunan").length}`);
}
```

Model, bu akıbetin kuralını kurar; model çerçevenin kendisi değildir. Kural ağaçlara bakar, durumun nerede durduğunu görmez.

## Yerel Durum

Yerel durum tek bir bileşenin kendi içinde tuttuğu veridir. Sepetteki her satırın adet sayacı bunun örneğidir: satırın dışında kimse bu sayıyı okumaz. Çerçevede yerel durum bir durum kancasıyla tutulur ve kanca, durum değişince o bileşenin yeniden çizilmesini ister. Yeniden çizim (render), bileşenin yeni görünüm ağacını üretmesidir; ağaç üretmek tek başına komut sayılmaz.

```jsx
// Platform kodu: QuantityRow
function QuantityRow({ name }) {
  const [qty, setQty] = useState(1);
  return (
    <Pressable onPress={() => setQty(qty + 1)}>
      <Text>{name}: {qty}</Text>
    </Pressable>
  );
}
```

Bu parça ölçülmez. Modelde durum, ağacı kuran işlevin girdisidir: işlev durumdan ağaç üretir, kural önceki ve sonraki ağacı karşılaştırır.

**UK1.** Model, durumdan ağaca giden işlevlerin saf olduğunu varsayar: aynı durum aynı ağacı verir. Gerçek bileşenlerde kancalar ve yan etkiler de vardır, ama bu derste ölçülen yalnız ağaçtır.

İki satırlı bir liste kuruyoruz. Her satırın adedi kendi durumudur ve `kalem` satırının adedi 1'den 2'ye çıkıyor.

```javascript
// main.mjs
import { el, reconcile, printOps, countFates } from "./fate.mjs";

function renderRows(counts) {
  return el("List", {}, Object.keys(counts).sort().map((name) =>
    el("Item", { ad: name, adet: counts[name] }, [], name)));
}

const ops = reconcile(
  renderRows({ kalem: 1, defter: 1 }),
  renderRows({ kalem: 2, defter: 1 }),
);
printOps(ops);
countFates(ops);
```

```text
korunan: /List
korunan: /List/Item[defter]
guncellenen: /List/Item[kalem]
korunan: 2
guncellenen: 1
kurulan: 0
sokulen: 0
komut: 1
```

Yerel durum değişince yalnız sahibi güncellenir. `Item[kalem]` güncellenendir, çünkü `adet` özelliği değişti; `Item[defter]` ve liste korunandır. Komut sayısı 1'dir. Durumun yerel kalması, değişikliğin etkisini de yerelde tutar.

## Paylaşılan Durum ve Durumun Yukarı Taşınması

Sepet sayısını yalnız bir satır okumaz. Üst çubuktaki rozet, alt çubuktaki toplam ve ödeme düğmesi aynı sayıya bakar. Bu veri artık tek bir bileşenin içinde duramaz, çünkü kardeş bileşenler birbirinin durumunu okuyamaz. Çözüm durumu, onu okuyan bileşenlerin ortak atasına taşımaktır: bu işleme **durumun yukarı taşınması** denir. Ata durumu tutar ve aşağıya özellik olarak verir.

Atanın altındaki bileşenler arasında derin bir zincir varsa özelliği her katmandan geçirmek ağırlaşır. O zaman paylaşılan durum bir **sağlayıcı**ya konur: ağacın üstüne yerleştirilen bu bileşen, altındaki her bileşenin durumu doğrudan okumasına izin verir. Paylaşılan durum kitaplıkları bu düzeneği hazır sunar; okuyan bileşen yalnız bir kanca çağırır.

```jsx
// Platform kodu: CartBadge
function CartBadge() {
  const count = useCartCount();
  return <Text>{count}</Text>;
}
```

**UK2.** Model, sağlayıcıyı görünüm ağacında düğüm olarak göstermez; yalnız sayıyı okuyan düğümleri gösterir. Sepet sayısı paylaşılan durumdadır ve `renderCart(state)` ağacı bu durumdan kurar.

```javascript
// cart.mjs — sepet ekraninin gorunum agacini paylasilan durumdan kurar
import { el } from "./fate.mjs";

export function renderCart(state) {
  return el("Screen", {}, [
    el("Header", {}, [
      el("Title", { metin: "Sepet" }),
      el("Badge", { sayi: state.sayi }),
    ]),
    el("List", {}, state.urunler.map((ad) => el("Item", { ad }, [], ad))),
  ]);
}
```

Kullanıcı sepetteki bir ürünü bir kez daha ekliyor. Sepet sayısı 2'den 3'e çıkıyor, ürünlerin listesi değişmiyor.

```javascript
// main.mjs
import { reconcile, printOps, countFates } from "./fate.mjs";
import { renderCart } from "./cart.mjs";

const urunler = ["kalem", "defter"];
const ops = reconcile(
  renderCart({ sayi: 2, urunler }),
  renderCart({ sayi: 3, urunler }),
);
printOps(ops);
countFates(ops);
```

```text
korunan: /Screen
korunan: /Screen/Header
korunan: /Screen/Header/Title
guncellenen: /Screen/Header/Badge
korunan: /Screen/List
korunan: /Screen/List/Item[kalem]
korunan: /Screen/List/Item[defter]
korunan: 6
guncellenen: 1
kurulan: 0
sokulen: 0
komut: 1
```

Tek bir durum değişikliği yapıldı ve iki düğüm farklı akıbet aldı. `/Screen/Header/Badge` güncellenendir, çünkü rozetin `sayi` özelliği değişti. Ürün satırları ve liste korunandır, çünkü onların özellikleri aynı kaldı. M30/K03'te bir yeniden hesaplamayı neyin tetiklediği sorulurdu. Bu kurs nedeni sormaz, etkiyi sınıflar: neden değil etki; aynı tetik bir düğümü günceller, ötekini korur.

Paylaşımın bedeli de bu ölçümde görünür. Bir durumu okuyan düğüm sayısı arttıkça aynı değişiklik daha çok komut doğurur. Bunu iki kurulumda karşılaştırıyoruz. Birinde rozet kendi sayacını tutar, alttaki toplam başka bir sayıyı gösterir. Ötekinde ikisi aynı paylaşılan durumu okur.

```javascript
// main.mjs
import { el, reconcile, countFates } from "./fate.mjs";

function renderPair(badge, total) {
  return el("Screen", {}, [
    el("Header", {}, [el("Badge", { sayi: badge })]),
    el("Footer", {}, [el("Total", { sayi: total })]),
  ]);
}

console.log("yerel:");
countFates(reconcile(renderPair(2, 2), renderPair(3, 2)));
console.log("paylasilan:");
countFates(reconcile(renderPair(2, 2), renderPair(3, 3)));
```

```text
yerel:
korunan: 4
guncellenen: 1
kurulan: 0
sokulen: 0
komut: 1
paylasilan:
korunan: 3
guncellenen: 2
kurulan: 0
sokulen: 0
komut: 2
```

Yerel kurulumda değişiklik tek düğümü günceller: komut 1. Paylaşılan kurulumda iki düğüm güncellenir: komut 2. Yerel kurulumda ekranın iki yeri farklı sayı gösterir: rozet 3, toplam 2. Paylaşılan kurulumda ikisi de 3 gösterir ve bunun bedeli bir komuttur. Hangi kurulumun doğru olduğu komut sayısından değil, ekranın tutarlı olmasından gelir. Kural bu yargıyı vermez; komutun bedelini söyler.

## Listeye Bir Öge Eklemek

Şimdiye dek durum değişikliği var olan bir özelliği değiştirdi. Çoğu gerçek değişiklik ise sayıyı değiştirmekle kalmaz, listeye bir öge de ekler. Sepete bir ürün eklenince iki şey olur: rozetin sayısı artar ve listede yeni bir satır belirir. İki etki aynı durumdan gelir ama ağaçta farklı akıbet alır; bunu ölçelim.

```javascript
// main.mjs
import { reconcile, printOps, countFates } from "./fate.mjs";
import { renderCart } from "./cart.mjs";

const ops = reconcile(
  renderCart({ sayi: 2, urunler: ["kalem", "defter"] }),
  renderCart({ sayi: 3, urunler: ["kalem", "defter", "silgi"] }),
);
printOps(ops.filter((op) => op.fate !== "korunan"));
countFates(ops);
```

```text
guncellenen: /Screen/Header/Badge
kurulan: /Screen/List/Item[silgi]
korunan: 6
guncellenen: 1
kurulan: 1
sokulen: 0
komut: 2
```

Rozet önceki ölçümlerdeki gibi güncellenendir. Yeni satır ise güncellenen değil kurulandır: önceki ağaçta bu anahtarla bir düğüm yoktu, kural da olmayan bir düğümü güncelleyemez. İlk iki ürünün satırları anahtarlarıyla eşleşir ve korunan kalır. Satırların anahtarı ürün adıdır; bu yüzden eklemenin eski satırlara dokunmadığını kural anahtar eşleşmesinden bilir, sıradan değil.

Bu ölçüm bir ayrımı da açıklar. Durum tek bir nesnedir, ama ağaçtaki etkisi parçalıdır: sayıyı gösteren düğüm güncellenir, listeye giren öge kurulur, dokunulmayan ögeler korunur. "Bir durum değişikliği bir komuttur" demek yanlıştır; komut sayısı, değişikliğin kaç düğüme yansıdığına bağlıdır.

## Karşı Örnek: Yukarı Taşımanın Maliyeti

Durumu yukarı taşımak her zaman iyi bir hamle değildir. Bir satırın adedi yalnız o satırı ilgilendiriyorsa, onu ekranın en üstündeki paylaşılan duruma taşımak kazanç getirmez. Veri artık ekranın tamamının durumudur; değişiklik üstteki durumu değiştirir ve o durumdan beslenen her düğüm karşılaştırmaya girer. Yukarıdaki iki kurulum ölçümü bunu gösterdi: paylaşılan kurulumda tek değişiklik iki komuttu, yerelde bir. Düğüm sayısı arttıkça fark büyür.

Yerelde bırakmanın bedeli ise tutarsızlıktır: aynı sayıyı iki yer gösteriyorsa ikisinin farklı sayı göstermesi bir hatadır. Karar bu yüzden bir kural değil bir tartıdır: veriyi kaç yerin okuduğuna ve bu yerlerin tutarlı olmasının gerekip gerekmediğine bakılır. Tutarlılık gerekiyorsa paylaşılan durumun bir komut fazlası kabul edilir; gerekmiyorsa yerel kalır.

## Durum Nerede Durmalı

Durumun yeri üç soruyla bulunur. Birincisi, kimin okuduğudur: yalnız bir bileşen okuyorsa yerel kalır. İkincisi, okuyanların ortak atasının nerede olduğudur: iki kardeş okuyorsa durum onların hemen üstündeki atada durur. Üçüncüsü, okuyanların ağacın uzak köşelerinde olup olmadığıdır: öyleyse sağlayıcı araya girer. Durumu gereğinden yukarıda tutmak ilk bakışta kolaylık gibi görünür, ama her değişiklikte o durumu okuyan tüm bileşenler yeniden çizim ister. Yeniden çizim komut değildir; kural ağaçları karşılaştırır ve yalnız farkı komut sayar. Yine de gereksiz yere çok bileşenin yeniden çizilmesi, çizim işinin boşuna artması demektir ve bu iş sonraki derslerde ayrı bir konu olarak ölçülür.

## Yaygın Yanılgılar

İlk yanılgı, "durum değişince ekran değişir" düşüncesidir. Ekran, yalnız durumdan ağaca giden işlev değişikliği ağaca yazarsa değişir. Sınırlayıcı ölçümde görülecek, ekrana yazılmayan bir alan hiçbir düğümü güncellemez.

İkinci yanılgı, "paylaşılan durum her zaman daha iyidir" düşüncesidir. Paylaşılan durum bir veriyi birçok yerden okunur kılar, ama bedelini de getirir: değişiklik okuyan düğüm sayısı kadar komut doğurur ve verinin kim tarafından değiştirildiğini izlemek zorlaşır. Bir satırın adedi gibi yalnız kendi bileşenini ilgilendiren veri yerelde kalmalıdır.

Üçüncü yanılgı, yerel ile paylaşılanı bir kez seçip bırakmaktır. Bir veri başta yerel olabilir ve ekrana yeni bir okuyan eklenince yukarı taşınır. Taşıma, kod düzeninin değişmesidir; görünüm ağacındaki düğümler aynı kalır, değişen yalnız hangi düğümün hangi durumu okuduğudur.

Dördüncü yanılgı, türetilebilen değeri ayrıca saklamaktır. Rozetin sayısı listenin uzunluğundan hesaplanabilir. Onu ayrı bir durum olarak tutmak, iki değerin birbirinden ayrışma ihtimalini doğurur: liste üç ürün gösterirken rozet iki yazabilir. Türetilebilen değer saklanmaz, her çizimde hesaplanır. Böylece listeye öge eklendiğinde rozet de, ekleme ölçümünde görüldüğü gibi, aynı değişiklikle güncellenir ve ikisinin ayrışması mümkün olmaz.

Beşinci yanılgı, durum ne kadar küçükse o kadar zararsız olduğunu varsaymaktır. Küçük bir durum da çok sayıda düğümden okunabilir. Maliyeti durumun büyüklüğü değil, onu okuyan düğüm sayısı belirler.

Altıncı yanılgı, ölçümün tek bir durum değişikliğini bütün uygulamanın davranışı saymaktır. Burada ölçülen, bir sepet ekranında bir değişikliğin etkisidir. Başka bir ekranda, daha fazla okuyanla ya da daha derin bir ağaçta sayılar değişir; değişmeyen şey, akıbetin sınıflandırılma biçimidir.

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

Durumun değişmesi ile bir düğümün güncellenmesi aynı olay değildir. Aşağıda sepet durumuna ekranda gösterilmeyen bir alan, `kupon`, ekleniyor. Önce yalnız bu alan değişiyor, sonra sayı değişiyor.

```javascript
// main.mjs
import { reconcile, printOps, countFates } from "./fate.mjs";
import { renderCart } from "./cart.mjs";

const urunler = ["kalem", "defter"];
const focus = (op) => op.path === "/Screen/Header/Badge";
const first = reconcile(
  renderCart({ sayi: 2, urunler, kupon: "yaz" }),
  renderCart({ sayi: 2, urunler, kupon: "kis" }),
);
const second = reconcile(
  renderCart({ sayi: 2, urunler, kupon: "kis" }),
  renderCart({ sayi: 3, urunler, kupon: "kis" }),
);
console.log("kupon degisti:");
countFates(first);
console.log("sayi degisti:");
printOps(second.filter(focus));
```

```text
kupon degisti:
korunan: 7
guncellenen: 0
kurulan: 0
sokulen: 0
komut: 0
sayi degisti:
guncellenen: /Screen/Header/Badge
```

Kupon değişti, ama `renderCart` bu alanı ağaca yazmıyor; iki ağaç aynıdır ve komut 0'dır. Durum değişti, ağaç değişmedi. Sayı değişince `/Screen/Header/Badge` güncellenendir. Kural durumun yerini ya da ne kadar değiştiğini görmez; yalnız ağaçta görünen özelliklerin karşılaştırmasını görür. Bu yüzden durum yönetimi tek başına başarım ölçüsü değildir: durumun çok güncellenmesi, çok komut doğurması anlamına gelmez.

## Özet

- Bu dersin akıbeti: güncellenen. Sepet sayısı değişince `/Screen/Header/Badge` düğümü, `sayi` özelliği değiştiği için güncellenen çıktı.
- Aynı durum değişikliği rozeti güncelledi, ürün listesini korunan bıraktı: aynı tetik iki düğüme iki ayrı akıbet verdi.
- Yerel durum değişikliğin etkisini sahibi olan düğümde tutar; paylaşılan durum okuyan düğüm sayısı kadar komut doğurur.
- Kupon gibi ağaca yazılmayan bir durum değişince hiçbir düğüm güncellenmez: durum değişikliği ile komut aynı şey değildir.
- Kural durumun yerini görmez; yalnız önceki ve sonraki ağacı karşılaştırır.

## Sonraki Adım

Bu derste durum uygulamanın içinde değişti. Uygulamanın en önemli veri kaynağı ise dışarıdadır: sunucu. Sıradaki ders, `Ağ ve Veri`, bir istek yanıt verince yükleniyor göstergesinin ve listenin ağaçta ne yaşadığını ölçer.
