---
title: 'Yerel Durum'
source: 'https://academia.sh/tr/kurslar/bilesen-tabanli-gelistirme/yerel-durum'
course: 'Bileşen Tabanlı Arayüz Geliştirme'
language: tr
updated: '2026-08-17T18:09:13+00:00'
license: 'CC BY-SA 4.0'
---

# Yerel Durum

Bileşenin oluşturmalar arası yaşayan değeri; durum yuvalarının çağrı sırasına bağlanması, güncellemenin kuyruğa alınması, tek turdaki güncellemelerin toplu işlenmesi, eskimiş değer tuzağı ve durumun ağaçta nereye konacağı.

Önceki ders ağacın nasıl güncellendiğini çözdü: iki oluşturmanın ürettiği ağaçlar
karşılaştırılıyor, aradaki fark en küçük dokunuşlarla belgeye uygulanıyor. Uzlaşma
bittiğinde geriye tek bir soru kalır. Karşılaştırma her zaman bir yeniden çizimden sonra
yapılır — peki yeniden çizimi ne başlatır?

Yanıt, bileşenin kendi içinde tuttuğu değerdir. Kuzey Yamaç Ölçüm İstasyonu sayfasındaki
süzgeç paneli hangi ölçüm türünün seçili olduğunu bilir, ölçüm tablosu hangi sütuna göre
sıralandığını bilir, her ölçüm rozeti açılıp açılmadığını bilir. Bu değerler sunucudan
gelmez, üst bileşenden verilmez ve sayfa yenilenene kadar yaşar. Bu derste bunlara
**yerel durum (local state)** denir; dersin konusu durumun nerede saklandığı, bir
güncellemenin ne zaman görünür olduğu ve bir turdaki üç güncellemenin kaç oluşturma
ürettiğidir.

## Durum Nerede Yaşar

Bir bileşenin gövdesi her oluşturmada baştan çalışan bir işlevdir. İşlev gövdesinde
tanımlanan yerel değişkenler her çağrıda sıfırlanır; ikinci oluşturmada birinci
oluşturmadan kalan hiçbir şey yoktur. Durumun bu gövdenin dışında bir yerde yaşaması
gerekir.

Yaşadığı yer, bileşenin **örneğidir**. Ağaçtaki her bileşen konumuna karşılık bir örnek
kaydı tutulur ve bu kayıtta bir yuva listesi bulunur. Gövde çalışırken çalışma zamanı bir
imleç tutar: gövde her durum isteğinde imleci bir ilerletir ve o sıradaki yuvayı verir.
İlk oluşturmada yuva yoksa başlangıç değeriyle açılır, sonraki oluşturmalarda var olan
yuva okunur.

Gövdenin bu yuvaya erişmek için çağırdığı işleve **durum kancası (state hook)** denir.
Kanca iki şey döndürür: yuvadaki güncel değer ve o yuvaya yazma isteği gönderen bir
işlev. Değer okunur, yazma isteği çağrılır; ikisinin arasında doğrudan bir atama yoktur.

## Güncelleme Bir İstek, Atama Değildir

Yazma işlevinin adı yanıltıcı olabilir. Çağrıldığı anda yuvaya yazmaz; bir güncelleme
isteğini kuyruğa koyar ve o bileşeni kirli olarak işaretler. Kuyruk, çalışan kod bittikten
sonra boşaltılır. Aşağıdaki model bu kuyruğu, kuyruğun boşaltılmasını ve boşaltmanın kaç
oluşturma ürettiğini görünür kılar.

```js
// durum-kuyrugu.mjs — yerel durum, guncelleme kuyrugu ve toplu isleme
let etkinOrnek = null;
let cizimSayisi = 0;
const kuyruk = [];

function durumKancasi(ilk) {
  const o = etkinOrnek;
  const i = o.imlec++;
  if (o.yuvalar.length === i) o.yuvalar.push(typeof ilk === "function" ? ilk() : ilk);
  return [o.yuvalar[i], (yeni) => { kuyruk.push({ o, i, yeni }); }];
}

function olustur(ornek) {
  etkinOrnek = ornek;
  ornek.imlec = 0;
  const cikti = ornek.govde();
  etkinOrnek = null;
  cizimSayisi++;
  console.log(`  cizim ${cizimSayisi}: ${cikti}`);
}

// Olay isleyicisi bittiginde calisir: kuyruk bosaltilir, her ornek bir kez cizilir.
function turuBitir() {
  const kirliler = [];
  for (const is of kuyruk) {
    const eski = is.o.yuvalar[is.i];
    is.o.yuvalar[is.i] = typeof is.yeni === "function" ? is.yeni(eski) : is.yeni;
    if (!kirliler.includes(is.o)) kirliler.push(is.o);
  }
  console.log(`  [tur sonu] kuyrukta ${kuyruk.length} guncelleme, ${kirliler.length} ornek kirli`);
  kuyruk.length = 0;
  for (const o of kirliler) olustur(o);
}

const rozet = { ad: "rozet", yuvalar: [], imlec: 0, dis: null };
rozet.govde = () => {
  const [deger, yazDeger] = durumKancasi(0);
  const [birim, yazBirim] = durumKancasi("C");
  rozet.dis = { deger, yazDeger, yazBirim };
  return `deger=${deger} birim=${birim}`;
};

console.log("A. dogrudan deger yazan uc guncelleme, tek olay icinde");
olustur(rozet);
rozet.dis.yazDeger(rozet.dis.deger + 1);
rozet.dis.yazDeger(rozet.dis.deger + 1);
rozet.dis.yazBirim("F");
console.log(`  yazmadan hemen sonra govdedeki deger: ${rozet.dis.deger}`);
turuBitir();

console.log("B. ayni islem, guncelleyici islevle");
rozet.yuvalar = [0, "C"];
cizimSayisi = 0;
olustur(rozet);
rozet.dis.yazDeger((onceki) => onceki + 1);
rozet.dis.yazDeger((onceki) => onceki + 1);
rozet.dis.yazBirim("F");
turuBitir();

console.log("C. iki ayri turda yapilan ayni iki guncelleme");
rozet.yuvalar = [0, "C"];
cizimSayisi = 0;
olustur(rozet);
rozet.dis.yazDeger((onceki) => onceki + 1);
turuBitir();
rozet.dis.yazDeger((onceki) => onceki + 1);
turuBitir();
```

```
A. dogrudan deger yazan uc guncelleme, tek olay icinde
  cizim 1: deger=0 birim=C
  yazmadan hemen sonra govdedeki deger: 0
  [tur sonu] kuyrukta 3 guncelleme, 1 ornek kirli
  cizim 2: deger=1 birim=F
B. ayni islem, guncelleyici islevle
  cizim 1: deger=0 birim=C
  [tur sonu] kuyrukta 3 guncelleme, 1 ornek kirli
  cizim 2: deger=2 birim=F
C. iki ayri turda yapilan ayni iki guncelleme
  cizim 1: deger=0 birim=C
  [tur sonu] kuyrukta 1 guncelleme, 1 ornek kirli
  cizim 2: deger=1 birim=C
  [tur sonu] kuyrukta 1 guncelleme, 1 ornek kirli
  cizim 3: deger=2 birim=C
```

## Toplu İşleme

A bölümünün ilk okunacak satırı, yazma çağrılarından hemen sonra gövdedeki değerin hâlâ
sıfır olmasıdır. Gövde, o oluşturmada okuduğu değeri bir kapanışta tutar; kapanış o
oluşturmaya aittir ve yazma isteği onu değiştirmez. Bir oluşturma boyunca durum sabittir.
Bu, bir kısıt değil bir güvencedir: aynı gövde içinde bir değerin bir yerde eski, başka
bir yerde yeni okunması olanaksızdır.

İkinci okunacak satır oluşturma sayısıdır. Üç güncelleme kuyruğa girmiş, tur sonunda
kuyruk boşaltılmış ve **tek** bir oluşturma yapılmıştır. Bir turdaki bütün güncellemelerin
biriktirilip tek oluşturmayla karşılanmasına **toplu işleme (batching)** denir. Toplu
işleme olmasaydı üç yazma üç oluşturma üretirdi; her oluşturma bir uzlaşma turu demek
olduğu için maliyet üçe katlanırdı. Dahası ara oluşturmalar tutarsız görünürdü: değer
güncellenmiş ama birim henüz eski olurdu.

Toplu işlemenin sınırı tur sınırıdır. C bölümünde aynı iki güncelleme iki ayrı turda
yapılmış ve iki oluşturma üretmiştir. Bir olay işleyicisi içinde yapılan güncellemeler
aynı gruba girer; bir zamanlayıcı geri çağırımından ve bir ağ yanıtından gelen
güncellemeler ayrı turlardır ve genellikle ayrı oluşturmalar üretir.

## Eskimiş Değer ve Güncelleyici İşlev

A ile B arasındaki tek fark yazma çağrısının biçimidir; sonuç birde ve ikide ayrılır.

A'da her iki çağrı da `deger + 1` ifadesini kendi kapanışındaki sıfırdan hesaplamış, ikisi
de bire yazmıştır. İkinci yazma birinciyi ezmez, aynı sonucu yeniden yazar. Bu, **eskimiş
değer (stale value)** tuzağıdır ve tek bir turda aynı yuvaya iki kez yazan her kodda
belirir: sayaç iki artırma sonunda bir artmıştır.

B'de yazma çağrısına değer değil bir işlev verilmiştir. Kuyruk boşaltılırken bu işlev, o
andaki yuva değeriyle çağrılır; birinci istek sıfırdan bire, ikincisi birden ikiye taşır.
Buradan bağlayıcı bir kural çıkar: **yeni değer eski değere bağlıysa güncelleyici işlev
yazılır.** Yeni değer eskisinden bağımsızsa — süzgecin seçilen türü, panelin açık olması —
doğrudan değer yazmak yeterlidir.

## Çağrı Sırasının Değişmezliği

Modelde yuvalar ada göre değil imlece göre bulunur. Bunun bir bedeli vardır: gövdenin her
oluşturmada durum kancasını **aynı sırayla ve aynı sayıda** çağırması gerekir. Kanca
çağrısı bir koşulun içine alınırsa, koşul değiştiği oluşturmada imleç kayar ve ikinci
yuvanın değeri birinci yuvadan okunur. Hata sessizdir; birbiriyle ilgisiz iki değer yer
değiştirir.

Bu yüzden durum çağrıları gövdenin en üstünde, koşulsuz ve döngüsüz yazılır. Koşullu bir
durum gerekiyorsa koşul kancanın etrafına değil, kancadan sonraki kullanıma konur. Ada
göre çözümleme yapan tasarımlarda bu kısıt yoktur; buna karşılık ad çakışmalarını
denetlemek gerekir. Sıraya dayanan tasarımın kazancı, hiçbir ad kaydı tutmadan sabit
zamanda yuva bulmasıdır.

## Durumun Ağaçtaki Yeri

Durumun hangi bileşende tutulacağı bir tasarım kararıdır ve doğrudan ölçülebilir bir
maliyeti vardır. Bir yuva değiştiğinde o bileşen ve altındaki bütün ağaç yeniden
oluşturulur; kardeşler ve atalar etkilenmez.

```js
// durumun-yeri.mjs — ayni durumun iki ayri dugumde tutulmasinin olusturma maliyeti
const AGAC = {
  ad: "sayfa",
  cocuklar: [
    { ad: "baslik", cocuklar: [] },
    { ad: "suzgec-paneli", cocuklar: [{ ad: "suzgec-dugmesi", cocuklar: [] },
                                      { ad: "suzgec-listesi", cocuklar: [] }] },
    { ad: "olcum-tablosu", cocuklar: [{ ad: "satir-1", cocuklar: [] },
                                      { ad: "satir-2", cocuklar: [] },
                                      { ad: "satir-3", cocuklar: [] }] },
  ],
};

function bul(dugum, ad) {
  if (dugum.ad === ad) return dugum;
  for (const c of dugum.cocuklar) { const s = bul(c, ad); if (s) return s; }
  return null;
}

// Durumu tutan dugum ve butun alt agaci yeniden olusturulur.
function altAgac(dugum, toplanan = []) {
  toplanan.push(dugum.ad);
  for (const c of dugum.cocuklar) altAgac(c, toplanan);
  return toplanan;
}

const toplam = altAgac(AGAC).length;
for (const sahip of ["sayfa", "suzgec-paneli"]) {
  const cizilen = altAgac(bul(AGAC, sahip));
  console.log(`durum "${sahip}" dugumunde:`);
  console.log(`  yeniden olusturulan ${cizilen.length}/${toplam}: ${cizilen.join(", ")}`);
}
```

```
durum "sayfa" dugumunde:
  yeniden olusturulan 9/9: sayfa, baslik, suzgec-paneli, suzgec-dugmesi, suzgec-listesi, olcum-tablosu, satir-1, satir-2, satir-3
durum "suzgec-paneli" dugumunde:
  yeniden olusturulan 3/9: suzgec-paneli, suzgec-dugmesi, suzgec-listesi
```

Süzgeç panelinin açık olup olmadığı yalnız paneli ilgilendirir. Bu değer sayfa kökünde
tutulursa her açma kapama dokuz bileşeni yeniden çizer; panelde tutulursa üçünü.
Durumu onu kullanan en alt bileşende tutmaya **durumun yerelde tutulması (state
colocation)** denir ve varsayılan tercih budur.

Ters yön de gereklidir. Seçili ölçüm türünü hem süzgeç paneli hem ölçüm tablosu bilmek
zorundadır. Aynı değerin iki kopyası iki ayrı yuvada tutulursa ikisi kaçınılmaz olarak
ayrışır. Böyle bir değer, iki bileşenin **ortak atasında** tutulur ve aşağıya verilir;
buna Bileşen Kavramı dersinde **durumun yukarı taşınması** dendi. Ölçütü tek cümleyle yazmak
olanaklıdır: durum, ona ihtiyaç duyan bütün bileşenlerin en yakın ortak atasında durur —
ne daha yukarıda, ne daha aşağıda.

## Başlangıç Değeri ve Tembel Kurulum

Modeldeki kanca başlangıç değerini yalnız yuva ilk açılırken kullanır; sonraki
oluşturmalarda o değer hiç okunmaz. Bunun bir sonucu vardır: başlangıç değeri pahalı bir
hesaptan geliyorsa — yerel depolamadan okuma, uzun bir listeyi ayrıştırma — hesap her
oluşturmada boşuna yapılır. Kanca değer yerine bir işlev de kabul ederse hesap yalnız ilk
oluşturmada çalışır. Buna **tembel kurulum (lazy initialization)** denir.

İkinci sonuç daha sık şaşırtır: üst bileşenden gelen bir değer başlangıç değeri olarak
verildiğinde, o değerin sonradan değişmesi yuvayı güncellemez. Yuva ilk oluşturmada
dondurulmuştur. Üstten gelen değeri izlemesi gereken bir görünüm için o değer durum
olmamalı, doğrudan kullanılmalıdır.

## Özet

- Yerel durum, bileşen gövdesinde değil bileşen örneğindeki bir yuvada yaşar; gövde her
  oluşturmada yuvaları çağrı sırasına göre okur.
- Yazma işlevi atama yapmaz, kuyruğa bir güncelleme isteği koyar; bir oluşturma boyunca
  okunan değer sabit kalır.
- Bir turdaki bütün güncellemeler toplu işlenir ve tek oluşturma üretir; ayrı turlardaki
  güncellemeler ayrı oluşturmalar üretir.
- Yeni değer eski değere bağlıysa güncelleyici işlev yazılır; doğrudan değer yazmak aynı
  turdaki ikinci güncellemede eskimiş değer üretir.
- Durum kancaları koşulsuz ve döngüsüz çağrılır, çünkü yuvalar ada göre değil sıraya göre
  bulunur.
- Durum, onu kullanan bileşenlerin en yakın ortak atasında tutulur; daha yukarıda tutmak
  gereksiz oluşturma, iki yerde tutmak ayrışma üretir.

## Sonraki Adım

Bu dersin kurduğu döngü kendi içine kapalıdır: durum değişir, gövde yeniden çalışır, ağaç
uzlaşır. Gövdenin bu döngüde tek bir görevi vardır ve o da girdilerden bir çıktı
hesaplamaktır. Oysa ölçüm istasyonu sayfasının yapması gereken işlerin bir bölümü bu
hesabın dışındadır: sunucudan ölçüm çekmek, kaydırma olayına dinleyici bağlamak, seçili
süzgeci yerel depolamaya yazmak, bir zamanlayıcı kurmak. Bunlar gövdenin içine
yazılamaz — gövde bir çıktı hesaplar, dış dünyaya dokunmaz. Sonraki ders bu işlerin nereye
yazıldığını, ne zaman çalıştığını ve kurdukları şeyi ne zaman sökmek gerektiğini ele alır.
