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

# Bileşen Kavramı

Görünüm işlevinin parçalara ayrılması; girdi özelliği, çıktı geri çağrısı ve yerel durumdan oluşan sözleşme, bileşen örneğinin kimliği, yeniden çizimin yayıldığı alan ve durumun hangi bileşende durduğu.

Önceki dersin görünüm işlevi panonun tamamını tek gövdede betimliyordu. On beş rozet, bir
ölçüm tablosu ve bir süzgeç paneli aynı işleve sığdığında iki şey birden kaybolur: gövde
okunamaz hâle gelir ve hiçbir parçası tek başına yeniden kullanılamaz.

Bu ders işlevi parçalara ayırır. Ayrımın birimine **bileşen (component)** denir: kendi
görünüm tanımını üreten, dışarıyla üç tanımlı kanaldan konuşan bir işlev.

## Bileşenin Üç Kanalı

Bir bileşenin dış dünyayla ilişkisi üç kanalla sınırlıdır.

**Girdi özelliği (prop)**, ebeveynin çocuğa verdiği değerdir. Bağlam açıkken kısaca
**özellik** de denir. Yönü tek yönlüdür ve okunurdur: çocuk aldığı değeri değiştiremez. Ölçüm rozetinin girdisi ölçümün adı, değeri,
birimi ve eşiğidir.

**Çıktı**, çocuğun ebeveyne bildirdiği olaydır. Çocuk bir karar vermez, olan biteni
yukarıya bildirir; kararı durumu tutan taraf verir. Süzgeç paneli hangi seçeneğe
tıklandığını bildirir, hangi süzgecin uygulanacağına karar vermez. Bildirimin taşıyıcısı,
girdi olarak verilen bir **geri çağrıdır**.

**Yerel durum (local state)**, yalnızca bileşenin kendisini ilgilendiren ve dışarıdan
görünmeyen değerdir. Rozetin ayrıntı bölümünün açık olup olmadığı buna örnektir: hiçbir
başka parça bu bilgiye gerek duymaz.

Sözleşmenin tamamı bu üç kanaldır. Bileşenin ebeveynine ulaşan başka bir yolu, kardeşine
doğrudan erişimi ya da ağaçtan okuduğu gizli bir değeri yoktur.

## Bileşen Ağacı ve Örnek Kimliği

Bileşenler birbirini kullanır ve bir ağaç oluşturur. Bu ağaç belge ağacı değildir: her
bileşen bir belge düğümüne karşılık gelmek zorunda değildir, tek bir bileşen onlarca düğüm
üretebilir.

Ağaçtaki her konuma bir **bileşen örneği** karşılık gelir. Örnek, yerel durumun yaşadığı
yerdir ve yeniden çizimler arasında korunur.

```js
// bilesen-calisma-zamani.mjs — girdi, cikti ve yerel durumu olan kucuk bir bilesen modeli
const oge = (ad, ozn = {}, ...cocuklar) =>
  ({ tur: "oge", ad, ozn, cocuklar: cocuklar.flat() });
const kur = (islev, girdi = {}) => ({ tur: "bilesen", islev, girdi });

const ornekler = new Map();          // kimlik → { yerel, islev, girdi }
let sayac = new Map();               // bilesen adi → cizim sayisi

function oturum(kimlik) {
  const kayit = ornekler.get(kimlik);
  return {
    // Yerel durum ornege aittir; ayarlanmasi yalnizca bu ornegi yeniden cizer.
    yerel(ad, baslangic) {
      if (!kayit.yerel.has(ad)) kayit.yerel.set(ad, baslangic);
      return [kayit.yerel.get(ad), (yeni) => {
        kayit.yerel.set(ad, yeni);
        cizBilesen(kimlik, kayit.islev, kayit.girdi);
      }];
    },
  };
}

function cizBilesen(kimlik, islev, girdi) {
  if (!ornekler.has(kimlik)) ornekler.set(kimlik, { yerel: new Map() });
  const kayit = ornekler.get(kimlik);
  kayit.islev = islev; kayit.girdi = girdi;
  sayac.set(islev.name, (sayac.get(islev.name) ?? 0) + 1);
  return cizDugum(islev(Object.freeze(girdi), oturum(kimlik)), kimlik);
}

function cizDugum(tanim, yol) {
  if (typeof tanim === "string") return tanim;
  if (tanim.tur === "bilesen")
    return cizBilesen(`${yol}/${tanim.islev.name}`, tanim.islev, tanim.girdi);
  return { ad: tanim.ad, ozn: tanim.ozn,
    cocuklar: tanim.cocuklar.map((c, i) => cizDugum(c, `${yol}/${i}`)) };
}

// --- Bilesenler -------------------------------------------------------------
// Girdi: deger, birim, asim. Cikti: yok. Yerel durum: ayrinti acik mi.
function OlcumRozeti(girdi, { yerel }) {
  const [acik, ayarla] = yerel("acik", false);
  return oge("div", { class: girdi.asim ? "rozet asim" : "rozet", ac: () => ayarla(!acik) },
    `${girdi.ad}: ${girdi.deger} ${girdi.birim}`,
    acik ? oge("small", {}, `eşik ${girdi.esik} ${girdi.birim}`) : "");
}

// Girdi: secenekler, secili. Cikti: secildi geri cagrisi.
function SuzgecPaneli(girdi) {
  return oge("div", { class: "suzgec" }, girdi.secenekler.map((s) =>
    oge("button", { secili: s === girdi.secili, tikla: () => girdi.secildi(s) }, s)));
}

function OlcumTablosu(girdi) {
  return oge("ul", { class: "tablo" }, girdi.olcumler.map((o) =>
    kur(OlcumRozeti, { ...o, asim: o.deger >= o.esik })));
}

function Pano(girdi) {
  const gorunen = girdi.suzgec === "tumu"
    ? girdi.olcumler : girdi.olcumler.filter((o) => o.tur === girdi.suzgec);
  return oge("section", { class: "pano" },
    oge("h2", {}, `Kuzey Yamaç — ${gorunen.length} / ${girdi.olcumler.length} ölçüm`),
    kur(SuzgecPaneli, { secenekler: ["tumu", "sicaklik", "nem"],
      secili: girdi.suzgec, secildi: girdi.suzgecSecildi }),
    kur(OlcumTablosu, { olcumler: gorunen }));
}

// --- Calistirma -------------------------------------------------------------
const OLCUMLER = [
  { ad: "Sıcaklık", tur: "sicaklik", deger: -4.2, birim: "°C", esik: 30 },
  { ad: "Bağıl nem", tur: "nem", deger: 72, birim: "%", esik: 90 },
  { ad: "Zemin ısısı", tur: "sicaklik", deger: 1.8, birim: "°C", esik: 30 },
  { ad: "Çiy noktası", tur: "nem", deger: 95, birim: "%", esik: 90 },
];
let durum = { suzgec: "tumu", olcumler: OLCUMLER };
const kokCiz = () => cizBilesen("kok", Pano, {
  ...durum,
  suzgecSecildi: (s) => { durum = { ...durum, suzgec: s }; kokCiz(); },
});
const bildir = (etiket) => {
  console.log(`${etiket.padEnd(30)} ${[...sayac].map(([a, n]) => `${a} ${n}`).join(", ")}`);
  sayac = new Map();
};

kokCiz();
bildir("ilk cizim");

// Ilk rozetin yerel durumu degisiyor: yalnizca o ornek yeniden cizilir.
const ROZET = [...ornekler.keys()].find((k) => k.endsWith("OlcumRozeti"));
console.log(`ilk rozet ornegi: ${ROZET}`);
oturum(ROZET).yerel("acik", false)[1](true);
bildir("bir rozetin yerel durumu");

// Panonun durumu degisiyor: kokten baslayan yeniden cizim.
ornekler.get("kok").girdi.suzgecSecildi("sicaklik");
bildir("panonun durumu");

console.log(`\nsuzgecten sonra o rozetin yerel durumu: ` +
  `${ornekler.get(ROZET).yerel.get("acik")}`);
console.log(`kayitli bilesen ornegi sayisi: ${ornekler.size}`);
```

```
ilk cizim                      Pano 1, SuzgecPaneli 1, OlcumTablosu 1, OlcumRozeti 4
ilk rozet ornegi: kok/2/OlcumTablosu/0/OlcumRozeti
bir rozetin yerel durumu       OlcumRozeti 1
panonun durumu                 Pano 1, SuzgecPaneli 1, OlcumTablosu 1, OlcumRozeti 2

suzgecten sonra o rozetin yerel durumu: true
kayitli bilesen ornegi sayisi: 7
```

## Yeniden Çizimin Yayıldığı Alan

Çıktının dört yeri okunmalıdır.

Birincisi, **örneğin kimliği ağaçtaki konumdan türetilir**. `kok/2/OlcumTablosu/0/OlcumRozeti`
yolu, panonun üçüncü çocuğundaki tablonun birinci rozetini gösterir. Yerel durum bu
kimliğe bağlanır; kimlik değişirse durum başka bir örneğe ait olur. Bu bağın kırıldığı yer
listelerdir ve konunun beşinci dersinin konusudur.

İkincisi, **yerel durum yalnızca kendi örneğini yeniden çizer**. Rozetin ayrıntısı
açıldığında tek bir çizim yapılmıştır; pano, süzgeç paneli ve tablo hiç çalışmamıştır.
Durumu olabildiğince aşağıda tutmanın somut karşılığı budur.

Üçüncüsü, **yukarıdaki durum aşağıyı tümüyle yeniden çizer**. Süzgeç seçildiğinde kökten
başlayan çizim beş bileşeni çalıştırmıştır. Bu, kalıtsal bir maliyet değil, saflığın
sonucudur: girdisi değişmiş olabilecek her çocuğun yeniden çalıştırılması gerekir. Çizim
sayısı ikide kalmıştır çünkü süzgeç görünen ölçümü ikiye düşürmüştür.

Dördüncüsü, **yerel durum yeniden çizimden sağ çıkmıştır**. Rozet yeniden çalıştırılmış ama
`acik` değeri korunmuştur; durum işlevin içinde değil, örnekte yaşar.

Son satır bir eksiği de gösterir: süzgeç iki rozeti ağaçtan çıkardığı hâlde yedi örnek
kayıtlı kalmıştır. Ağaçtan çıkan bileşenin örneğini ve kaynaklarını kaldırmak, çerçevenin
sökme sorumluluğudur; bu model onu yapmaz.

## Girdi Yazılamaz, Durumun Bir Sahibi Vardır

Sözleşmenin iki maddesi sıkça ihlal edilir: çocuk girdisine yazar, ya da ortak olması
gereken durum çocuğun içinde tutulur.

```js
// sozlesme.mjs — girdinin degistirilemezligi ve durumun sahibi
// 1) Girdi yalnizca okunur. Cerceve girdiyi donarak sozlesmeyi zorlar.
function OlcumRozeti(girdi) {
  girdi.deger = Math.round(girdi.deger);   // sozlesme ihlali
  return `${girdi.ad}: ${girdi.deger}`;
}
try {
  OlcumRozeti(Object.freeze({ ad: "Sıcaklık", deger: -4.2 }));
} catch (hata) {
  console.log(`girdiye yazma: ${hata.constructor.name} — ${hata.message}`);
}

// 2) "En fazla bir rozet secili" degismezi durumun nerede durduguna baglidir.
const ADLAR = ["Sıcaklık", "Bağıl nem", "Rüzgâr"];
const TIKLAMALAR = ["Sıcaklık", "Bağıl nem", "Rüzgâr"];

// A) Durum her rozetin icinde: rozet kendi seciliigini kendisi cevirir.
const rozetlerA = ADLAR.map((ad) => ({ ad, secili: false }));
const rozetA = (rozet) => { rozet.secili = !rozet.secili; };
for (const ad of TIKLAMALAR) rozetA(rozetlerA.find((r) => r.ad === ad));

// B) Durum ortak atada: rozet yalnizca olayi yukari bildirir.
let pano = { seciliAd: null };
const rozetB = (girdi) => girdi.secildi(girdi.ad);
for (const ad of TIKLAMALAR)
  rozetB({ ad, secili: pano.seciliAd === ad,
    secildi: (a) => { pano = { seciliAd: pano.seciliAd === a ? null : a }; } });

const seciliA = rozetlerA.filter((r) => r.secili).map((r) => r.ad);
const seciliB = pano.seciliAd ? [pano.seciliAd] : [];
console.log(`\ntiklama dizisi: ${TIKLAMALAR.join(" → ")}`);
console.log(`A) durum rozetlerde  → secili: [${seciliA}] (${seciliA.length} adet)`);
console.log(`B) durum ortak atada → secili: [${seciliB}] (${seciliB.length} adet)`);
console.log(`degismez ("en fazla bir secili") A: ${seciliA.length <= 1}, ` +
  `B: ${seciliB.length <= 1}`);

// A'da pano baslikta "1 rozet secili" yazamaz: sayi rozetlerin icinde dagilmistir.
console.log(`\npanonun okuyabildigi secim sayisi — A: yok, B: ${seciliB.length}`);
```

```
girdiye yazma: TypeError — Cannot assign to read only property 'deger' of object '#<Object>'

tiklama dizisi: Sıcaklık → Bağıl nem → Rüzgâr
A) durum rozetlerde  → secili: [Sıcaklık,Bağıl nem,Rüzgâr] (3 adet)
B) durum ortak atada → secili: [Rüzgâr] (1 adet)
degismez ("en fazla bir secili") A: false, B: true

panonun okuyabildigi secim sayisi — A: yok, B: 1
```

Birinci bölüm, girdiye yazmanın neden yasak olduğunu gösterir. Yazma başarılı olsaydı,
değişiklik ebeveynin nesnesine geçerdi ve ebeveyn durumunu değiştirmediği için yeniden
çizim tetiklenmezdi: durum değişmiş, görünüm değişmemiş olurdu. Bu, ilk dersteki kaymanın
aynısıdır. Girdi nesnesinin dondurulması ihlali sessiz bir soruna değil, konumu belli bir
hataya çevirir.

İkinci bölüm, durumun yerinin bir tercih değil bir doğruluk sorunu olduğunu gösterir.
Seçili olma durumu rozetlerin içine dağıtıldığında "en fazla bir rozet seçili" değişmezini
koruyacak bir yer kalmaz; üç tıklama üç seçili rozet üretir. Ortak atada tutulduğunda aynı
tıklama dizisi tek bir seçim bırakır, çünkü değeri yazan tek bir yer vardır.

Son satır ikinci sonucu ekler: dağıtılmış durum **okunamaz** da. Başlıkta kaç rozetin
seçili olduğunu yazmak isteyen pano, A düzeninde bu sayıya erişemez.

## Durum Nerede Durmalı

Karar iki ölçüte iner.

Bir değeri **yalnızca bir bileşen** okuyup yazıyorsa, o bileşenin yerel durumudur. Aşağıda
tutulan durum daha küçük bir alanı yeniden çizer ve bileşeni tek başına kullanılabilir
kılar.

Bir değeri **birden çok bileşen** okuyor ya da yazıyorsa, o değer bunların **en yakın ortak
atasına** taşınır. Bu taşımaya **durumun yukarı taşınması (lifting state up)** denir. Ata
değeri tutar, çocuklara girdi olarak verir, çocukların bildirdiği olaylarla günceller.

İki ölçüt de aynı ilkeye dayanır: her değerin tek bir sahibi olmalıdır. Aynı bilginin iki
yerde tutulması, ilk derste ağaç ile durum arasında görülen kaymanın bileşenler arasındaki
biçimidir.

Yükseltmenin bir bedeli vardır: değer ile onu kullanan bileşen arasındaki her katman
girdiyi taşımak zorunda kalır. Ara katmanların yalnızca aktarmak için taşıdığı girdiler
biriktiğinde, ağaç boyunca değer sağlamanın başka bir yolu gerekir; bu yol kursun ilerleyen
konusunda ele alınır.

## Özet

- Bileşen, dış dünyayla üç kanaldan konuşan bir görünüm işlevidir: okunur girdi özelliği,
  yukarı bildirilen çıktı ve dışarıdan görünmeyen yerel durum.
- Bileşen ağacı belge ağacından ayrıdır; ağaçtaki her konuma karşılık gelen bileşen örneği,
  yerel durumun yaşadığı ve yeniden çizimler arasında korunduğu yerdir.
- Yerel durum yalnızca kendi örneğini yeniden çizer; üstteki bir durum, altındaki bütün
  bileşenleri yeniden çalıştırır.
- Girdiye yazmak, durumu değiştirip yeniden çizim tetiklemediği için kaymaya yol açar;
  girdinin dondurulması ihlali erken yakalar.
- Birden çok bileşeni ilgilendiren durum en yakın ortak atada tutulur; dağıtılmış durum hem
  değişmezi koruyamaz hem de yukarıdan okunamaz.
- Her değerin tek bir sahibi olmalıdır; yükseltmenin bedeli, ara katmanların girdiyi
  yalnızca aktarmak için taşımasıdır.

## Sonraki Adım

Bu dersin bileşenleri görünüm tanımını işlev çağrılarıyla kurdu: her öge bir çağrı, her
öznitelik bir nesne alanı. Bir ölçüm tablosunun bütün yapısı bu biçimde yazıldığında
işaretlemenin şekli kaybolur; iç içe geçmiş çağrılar arasında hangi ögenin nerede
kapandığını okumak güçleşir. Sonraki ders işaretlemenin kendi söz diziminde yazılıp veriye
bağlanmasını ele alır: metnin içine ifade yerleştirmek, öznitelik değerini bir ifadeden
almak, olayı bir işleve bağlamak ve bunların hangi noktada kaçırma gerektirdiğini
belirlemek.
