---
title: 'Tepkisel Bağımlılık Takibi'
source: 'https://academia.sh/tr/kurslar/bilesen-tabanli-gelistirme/tepkisel-bagimlilik-takibi'
course: 'Bileşen Tabanlı Arayüz Geliştirme'
language: tr
updated: '2026-08-17T18:09:13+00:00'
license: 'CC BY-SA 4.0'
---

# Tepkisel Bağımlılık Takibi

Okuma anında kaydedilen bağımlılıkla kurulan ince taneli güncelleme; aynı tablo değişikliğinin bu ailede ürettiği iş miktarı, kayıt defterinin bedeli, elmas bağımlılıkta tutarlılık ve toplu yazma.

Önceki dersteki iş miktarının kaynağı tek bir eksikti: çerçeve neyin değiştiğini bilmiyor,
bulmak için karşılaştırıyordu. Bilseydi karşılaştırmaya gerek kalmazdı.

Bilmenin yolu, bir değerin nerede okunduğunu **okuma anında** kaydetmektir. Bir hesap
çalışırken hangi değerlere baktığı izlenir ve bu değerlerin her birine "beni okuyan şuydu"
kaydı düşülür. Değer yazıldığında, güncellenmesi gereken hesapların listesi zaten elde
olur. Bu aile, güncellemeyi bir arama problemi olmaktan çıkarıp bir **bildirim** problemine
çevirir.

## Bağlantı, Bileşen Değil

Bu ailede güncelleme birimi bileşen değildir. Bileşen işlevi bir kez çalışır, tepkisel
değerleri ve görünümün bu değerlere bağlandığı noktaları kurar, sonra bir daha çalışmaz.
Güncellenen şey, tek bir **bağlantıdır**: belgedeki bir metin düğümü, bir öznitelik ya da
bir sınıf adı.

Üç ilkel yeter. **Sinyal (signal)**, okunabilen ve yazılabilen bir değerdir. **Türetilmiş
değer**, başka değerlerden hesaplanan ve sonucu bellenen bir değerdir. **Etki**, kaynakları
değiştiğinde yeniden çalışan bir işlevdir; görünüme yazan kod buradadır. Bileşen Yaşam
Döngüsü ve Durum konusundaki üç kavramın aynısıdır; ayrım, burada bunların bileşene değil
doğrudan birbirine bağlanmasıdır.

## Aynı Değişiklik, Bu Kez Sayılmış

Önceki dersteki tabloyu aynı büyüklükte kuralım: iki yüz satır, tek bir hücrenin değeri
değişiyor.

```js
// sinyal.mjs — okuma anında kaydedilen bagimlilik ve ince taneli guncelleme
let sayac = { abonelik: 0, hesap: 0, etki: 0, yama: 0 };
const sifirla = () => (sayac = { abonelik: 0, hesap: 0, etki: 0, yama: 0 });

let izleyici = null;
const kuyruk = new Set();
const KIP = { sirali: true };   // false: degisiklik anlik ve derinlemesine yayilir
let topluDerinlik = 0;
const toplu = (fn) => { topluDerinlik++; try { fn(); } finally { if (--topluDerinlik === 0) bosalt(); } };

const kaydet = (kaynak) => {
  if (!izleyici) return;
  kaynak.aboneler.add(izleyici);
  izleyici.seviye = Math.max(izleyici.seviye, kaynak.seviye + 1);
  sayac.abonelik++;
};
const isaretle = (hesap) => {
  if (KIP.sirali) { if (!hesap.kirli) { hesap.kirli = true; kuyruk.add(hesap); } }
  else { hesap.kirli = true; hesap.calistir(); }
};
function bosalt() {
  while (kuyruk.size) {
    let en = null;
    for (const h of kuyruk) if (!en || h.seviye < en.seviye) en = h;   // seviye sirasi
    kuyruk.delete(en);
    if (en.kirli) en.calistir();
  }
}

function sinyal(ilk) {
  const d = { deger: ilk, aboneler: new Set(), seviye: 0 };
  return {
    oku() { kaydet(d); return d.deger; },
    yaz(v) {
      if (Object.is(v, d.deger)) return;
      d.deger = v;
      for (const a of [...d.aboneler]) isaretle(a);
      if (topluDerinlik === 0) bosalt();
    },
  };
}

function turetilmis(fn) {
  const d = { deger: undefined, aboneler: new Set(), seviye: 0, kirli: true };
  d.calistir = () => {
    const onceki = izleyici; izleyici = d;
    sayac.hesap++;
    const yeni = fn();
    izleyici = onceki;
    const degisti = !Object.is(yeni, d.deger);
    d.deger = yeni; d.kirli = false;
    if (degisti) for (const a of [...d.aboneler]) isaretle(a);
  };
  return { oku() { if (d.kirli) d.calistir(); kaydet(d); return d.deger; } };
}

function etki(fn) {
  const d = { aboneler: new Set(), seviye: 0, kirli: false };
  d.calistir = () => { const onceki = izleyici; izleyici = d; sayac.etki++; d.kirli = false; fn(); izleyici = onceki; };
  d.calistir();
  return d;
}

// --- 1. Iki yuz satirlik olcum tablosu: her hucre kendi baglantisini kurar ---
const SATIR_SAYISI = 200;
sifirla();
const belge = new Array(SATIR_SAYISI).fill("");
const sinyaller = Array.from({ length: SATIR_SAYISI }, (_, i) => sinyal(-10 + i * 0.1));
for (let i = 0; i < SATIR_SAYISI; i++) {
  etki(() => { belge[i] = `${sinyaller[i].oku().toFixed(1)} °C`; sayac.yama++; });
}
const esikAsan = turetilmis(() => sinyaller.filter((s) => s.oku() > 5).length);
let ozetMetni = "";
etki(() => { ozetMetni = `eşiği aşan: ${esikAsan.oku()}`; sayac.yama++; });
const kurulum = { ...sayac };

sifirla();
sinyaller[120].yaz(42.5);
const guncelleme = { ...sayac };

console.log("aşama       abonelik  türetilmiş hesap  etki çalışması  belge yazması");
const yaz = (ad, s) => console.log(`${ad.padEnd(11)} ${String(s.abonelik).padStart(8)} ${String(s.hesap).padStart(17)} ${String(s.etki).padStart(15)} ${String(s.yama).padStart(14)}`);
yaz("kurulum", kurulum);
yaz("güncelleme", guncelleme);
console.log("değişen hücrenin metni:", belge[120], "| özet:", ozetMetni);

// --- 2. Toplu yazma: iki yazma tek guncelleme ---
sifirla();
sinyaller[10].yaz(60);
sinyaller[11].yaz(70);
console.log("\niki ayrı yazma → türetilmiş hesap:", sayac.hesap, "| etki çalışması:", sayac.etki, "| özet:", ozetMetni);
sifirla();
toplu(() => { sinyaller[12].yaz(80); sinyaller[13].yaz(90); });
console.log("tek toplu yazma → türetilmiş hesap:", sayac.hesap, "| etki çalışması:", sayac.etki, "| özet:", ozetMetni);

// --- 3. Elmas bagimlilik: ayni kaynaktan turetilen iki deger ve onlari birlestiren ucuncu ---
const kutuk = [];
const kur = () => {
  const ham = sinyal(-4.2);
  const santigrat = turetilmis(() => `${ham.oku().toFixed(1)} °C`);
  const fahrenhayt = turetilmis(() => `${(ham.oku() * 1.8 + 32).toFixed(1)} °F`);
  const ozet = turetilmis(() => `${santigrat.oku()} / ${fahrenhayt.oku()}`);
  etki(() => kutuk.push(ozet.oku()));
  return ham;
};

console.log("\n--- seviye sirali yayilim ---");
KIP.sirali = true; kutuk.length = 0; sifirla();
kur().yaz(10);
console.log("etki çalışması:", sayac.etki, "| günlük:", JSON.stringify(kutuk));

console.log("\n--- anlik derinlemesine yayilim ---");
KIP.sirali = false; kutuk.length = 0; sifirla();
kur().yaz(10);
console.log("etki çalışması:", sayac.etki, "| günlük:", JSON.stringify(kutuk));
KIP.sirali = true;
```

```
aşama       abonelik  türetilmiş hesap  etki çalışması  belge yazması
kurulum          401                 1             201            201
güncelleme       202                 1               2              2
değişen hücrenin metni: 42.5 °C | özet: eşiği aşan: 50

iki ayrı yazma → türetilmiş hesap: 2 | etki çalışması: 4 | özet: eşiği aşan: 52
tek toplu yazma → türetilmiş hesap: 1 | etki çalışması: 3 | özet: eşiği aşan: 54

--- seviye sirali yayilim ---
etki çalışması: 2 | günlük: ["-4.2 °C / 24.4 °F","10.0 °C / 50.0 °F"]

--- anlik derinlemesine yayilim ---
etki çalışması: 3 | günlük: ["-4.2 °C / 24.4 °F","10.0 °C / 24.4 °F","10.0 °C / 50.0 °F"]
```

## İki Ailenin Sayıları

Güncelleme satırı önceki dersle yan yana konduğunda ayrım keskindir. Sanal ağaç ailesinde
tek hücrelik değişiklik 802 bileşen çağrısı, 1004 düğüm karşılaştırması ve 601 öznitelik
karşılaştırması üretmişti. Burada bir türetilmiş hesap, iki etki çalışması ve iki belge
yazması var. Ağaç hiç gezilmiyor, hiçbir karşılaştırma yapılmıyor.

İki belge yazmasının biri değişen hücre, diğeri eşik özeti. Özet, iki yüz sinyalin
tamamına bağlı bir türetilmiş değerdir; bu yüzden hangi hücre değişirse değişsin yeniden
hesaplanır. **Toplayan hesaplar ince taneliliğin dışında kalır**: bir değer her şeye
bağlıysa, her değişiklikte çalışır. Ailenin kazancı bağlantıların yerelliğinden gelir, veri
akışının yapısını değiştirmez.

Sayının küçüklüğü ölçek büyüdükçe daha da belirginleşir. Sanal ağaç ailesinde iş miktarı
satır sayısıyla doğru orantılıdır; burada değişen bağlantı sayısıyla orantılıdır. İki bin
satırlık bir tabloda ilk sayı on katına çıkar, ikincisi değişmez.

## Defterin Bedeli

Kurulum satırı bedeli gösteriyor: 401 abonelik, 201 etki çalışması. Her hücre için bir etki,
her etki için bir abonelik; artı özet hesabının iki yüz sinyale birden abone olması.

Bu, bellekte tutulan bir çizgedir. Her sinyal abone kümesi taşır, her hesap kaynak listesi
taşır. Sanal ağaç ailesinde böyle bir yapı yoktur: orada tutulan tek şey bir önceki ağaçtır
ve ilişkiler her karşılaştırmada yeniden türetilir. Burada ilişkiler kalıcıdır ve bellekte
yer kaplar.

Güncelleme satırındaki 202 abonelik ikinci bedeli gösteriyor. Bir hesap her çalıştığında
bağımlılıklarını **yeniden** kaydeder; koşullu bir okuma bir sonraki çalışmada başka bir
kaynağa bağlanabileceği için kayıt her seferinde tazelenmek zorundadır. Özet hesabı iki yüz
sinyali yeniden okuyup yeniden abone oluyor. Defterin bakımı da bir iş kalemidir.

Üçüncü bedel görünmez bağlantıdır. Bir değerin nerede okunduğu kaynak metinde
işaretlenmemiştir; okumanın kendisi kayıt yaptırır. Bir okumayı yanlış yere koymak — örneğin
bir etkinin dışına çıkarmak — bağlantıyı sessizce koparır ve görünüm güncellenmez. Konum
tabanlı kancalardaki çağrı sırası kuralı gibi, bu da dilin denetlemediği bir sözleşmedir.

## Elmas Bağımlılık ve Tutarlılık

Son iki bölüm, bildirim tabanlı bir sistemin en ince sorununu gösteriyor.

Ham ölçümden iki değer türetiliyor — santigrat ve fahrenhayt — ve üçüncü bir değer ikisini
birleştiriyor. Ham değer yazıldığında iki türetilmiş değer de geçersizleşir, ama sırayla
güncellenirler. Yayılım anlık ve derinlemesine yapılırsa, santigrat güncellendiği anda özet
de güncellenir; oysa fahrenhayt hâlâ eski değerindedir.

Günlükteki ikinci satır bunu gösteriyor: `10.0 °C / 24.4 °F`. Bu değer hiçbir zaman
gerçek olmadı — santigrat yeni, fahrenhayt eski. Buna **tutarsız ara değer (glitch)** denir
ve etkiyi bir kez fazladan çalıştırmakla kalmaz, o çalıştırmada yanlış bir görüntü üretir.

Seviye sıralı yayılımda bu olmuyor. Her hesaba, kaynaklarının en büyük seviyesinden bir
fazla seviye verilir; güncelleme kuyruğu seviye sırasıyla boşaltılır. Böylece bir hesap,
bütün kaynakları güncellendikten sonra çalışır. Günlükte yalnızca başlangıç değeri ve
tutarlı son değer var.

Bu, ailenin gerçekleştirim ayrıntısı gibi görünen ama doğrudan doğruluk taşıyan bir
özelliğidir. Bir çerçevenin tepkisel çekirdeği değerlendirilirken sorulacak sorulardan biri,
tutarsız ara değerlerin tanım gereği engellenip engellenmediğidir.

## Toplu Yazma

İkinci bölüm ikinci bir tutarlılık aracını gösteriyor. İki sinyale ayrı ayrı yazıldığında
özet hesabı iki kez çalışıyor ve etkiler dört kez tetikleniyor. Aynı iki yazma tek bir toplu
işlemde yapıldığında özet bir kez hesaplanıyor, etki sayısı üçe iniyor.

Kazanç yalnızca iş miktarı değildir. Toplu yazma, iki değişikliğin **tek bir geçiş** olarak
görünmesini sağlar; arada oluşan ve hiçbir zaman geçerli olmayan durum dışarıya sızmaz.
Bileşen Yaşam Döngüsü ve Durum konusundaki toplu işleme kavramının aynısıdır; burada
bileşen sınırına değil, açıkça işaretlenen bir bloğa bağlıdır.

## Ailenin Profili

Güncelleme birimi bağlantıdır; ince tanelilik tek bir metin düğümüne kadar iner. İş miktarı
üretilen ağacın büyüklüğüyle değil değişen bağlantı sayısıyla orantılıdır ve belleme çoğu
durumda gerekmez — türetilmiş değer zaten bellenmiştir.

Karşılığında çalışma zamanı, bağımlılık çizgesini kurmak ve bakımını yapmak zorundadır:
kurulum daha pahalıdır, bellek kullanımı bağlantı sayısıyla artar ve her hesap çalıştığında
kayıtlar tazelenir. Bileşen işlevinin bir kez çalışması, "her çizimde baştan" alışkanlığına
göre farklı bir zihinsel model ister; kurulumda okunan bir değer donar, izlenmesi için
tepkisel olarak okunması gerekir.

## Özet

- Bu ailede bağımlılık okuma anında kaydedilir; güncelleme birimi bileşen değil tek bir
  bağlantıdır.
- Aynı tek hücrelik değişiklik, sanal ağaç ailesinde 802 bileşen çağrısı ve 1004 düğüm
  karşılaştırması üretirken burada bir türetilmiş hesap ve iki belge yazması üretti.
- Toplayan hesaplar ince tanelilik dışında kalır: bütün sinyallere bağlı bir türetilmiş
  değer, hangi sinyal değişirse değişsin yeniden hesaplanır.
- Kayıt defteri bellekte tutulur ve bakım ister; her hesap çalıştığında bağımlılıklarını
  yeniden kaydeder.
- Anlık ve derinlemesine yayılım elmas bağımlılıkta tutarsız ara değer üretir; seviye sıralı
  yayılım bunu tanım gereği engeller.
- Toplu yazma hem iş miktarını azaltır hem de ara durumun dışarı sızmasını önler.

## Sonraki Adım

İki aile de defterini çalışma zamanında tutuyor: biri ağacı karşılaştırarak, diğeri
abonelikleri kaydederek. İkisinin de indirilen kodda bir karşılığı var — fark alma algoritması
ya da bağımlılık çizgesi düzeneği, sayfa açıldığı anda tarayıcıya inmek zorunda. Oysa hangi
ifadenin hangi değere bağlı olduğu, çoğu durumda kaynak metne bakarak da anlaşılabilir. Bir
şablonda bir metin düğümünün hangi değişkeni okuduğu yazılıdır. Sonraki ders, bu çıkarımı
kod çalışmadan önce yapan yaklaşımı ele alır: bağımlılıkları derleme zamanında çözen ve
çalışma zamanına yalnızca güncelleme kodunu bırakan bir dönüştürücü yazar.
