---
title: 'Bileşim Kalıpları'
source: 'https://academia.sh/tr/kurslar/bilesen-tabanli-gelistirme/bilesim-kaliplari'
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şim Kalıpları

Sarmalayan bileşen ile yuva tabanlı bileşimin karşılaştırması; seçenek patlaması, özellik zincirinin ölçülmesi, kalıtım yerine bileşim ve iki kalıbın hangi koşulda doğru olduğu.

Önceki konu tek bir bileşeni sonuna kadar götürdü: yerel durumu, yan etkilerinin
temizlenmesi, türetilmiş değerlerinin bellenmesi, hata yalıtımı ve ağacın dışına çizim.
Bileşen artık kendi başına eksiksiz bir birimdir. Ancak bir arayüz tek bileşenden oluşmaz.
Kuzey Yamaç Ölçüm İstasyonu sayfasında on beş ölçüm rozeti, bir ölçüm tablosu ve bir süzgeç
paneli var; üçü de aynı yapı taşlarından kuruluyor.

Bu ders, tek bileşen çözüldükten sonra kalan soruyu ele alır: iki bileşen bir araya
getirilirken hangisi diğerinin neyini bilecek? Yanıtın iki ayrı kalıbı vardır ve aralarındaki
seçim, bileşenin ömrü boyunca ne kadar değişeceğini belirler.

## İki Kalıp

**Bileşim (composition)**, bir bileşenin başka bileşenlerden kurulmasıdır. (Terim M14/K03
Düzen Sistemleri kursunda çizim katmanlarının birleştirilmesi için de kullanılmıştı; burada
kastedilen bileşen ağacının kurulmasıdır.) İki kalıbı vardır.

**Sarmalama.** Bir bileşen, başka bir bileşeni içeride çağırır ve dışarıya kendi özellik
kümesini sunar. (Bileşen Kavramı dersinde tanımlanan girdi özelliği, bu konu boyunca kısaca
**özellik** diye anılır.) Çağıran, sarmalananı hiç görmez; yalnızca sarmalayanın
özelliklerini doldurur. Yapı bileşenin içinde sabittir.

**Yuva tabanlı bileşim.** Bileşen, iç yapısında bir delik bırakır ve o deliğe konacak ağacı
dışarıdan alır. Ne konacağını çağıran belirler; bileşen yalnızca nereye konacağını bilir.
Web Bileşenleri konusundaki Şablonlar ve Yuvalar dersinde bu, tarayıcının kendi yuva atama
algoritmasıyla gösterilmişti; çerçeve düzeyinde aynı fikir bileşenin bir özelliği olarak
geçer: değeri metin ya da sayı değil, bir ağaç parçasıdır.

İkisi aynı çıktıyı üretebilir. Ayrıştıkları yer çıktı değil, değişim karşısındaki davranıştır.

## Seçenek Patlaması

Ölçüm rozetiyle başlayalım. İlk sürümde rozet başlığı, değeri ve birimi çiziyor. Sonra
eşik aşımını göstermesi isteniyor; sonra kaynağın adını, sonra eğilim okunu, sonra bir
yenileme düğmesini, sonra bir not satırını.

Sarmalayan kalıpta her yeni istek bir mantıksal özellik ve bir dallanma ekler.

```js
// bilesim.mjs — sarmalayan bilesen ile yuva tabanli bilesimin karsilastirmasi
const oge = (ad, ozn = {}, ...cocuklar) => ({ ad, ozn, cocuklar: cocuklar.flat().filter(Boolean) });
const metin = (deger) => ({ ad: "#metin", ozn: {}, cocuklar: [], metin: deger });

// Ortak cekirdek: basligi, degeri ve birimi cizen rozet.
const cekirdek = ({ baslik, deger, birim }, ...ek) =>
  oge("div", { class: "rozet" },
    oge("span", { class: "rozet-baslik" }, metin(baslik)),
    oge("output", { class: "rozet-deger" }, metin(`${deger} ${birim}`)),
    ...ek);

// (a) Sarmalayan bilesen: her yeni ihtiyac bir mantiksal ozellik ve bir dallanma ekler.
function rozetSarmalayanV1({ baslik, deger, birim, esikAsildi, kaynakGoster, kaynak }) {
  const ek = [];
  if (esikAsildi) ek.push(oge("span", { class: "rozet-uyari" }, metin("esik asildi")));
  if (kaynakGoster) ek.push(oge("small", { class: "rozet-kaynak" }, metin(kaynak)));
  return cekirdek({ baslik, deger, birim }, ...ek);
}

// Altinci ihtiyac geldiginde ayni govde yeniden acilir.
function rozetSarmalayanV2({ baslik, deger, birim, esikAsildi, kaynakGoster, kaynak,
                             egilim, yenileDugmesi, notMetni }) {
  const ek = [];
  if (esikAsildi) ek.push(oge("span", { class: "rozet-uyari" }, metin("esik asildi")));
  if (kaynakGoster) ek.push(oge("small", { class: "rozet-kaynak" }, metin(kaynak)));
  if (egilim) ek.push(oge("span", { class: "rozet-egilim" }, metin(egilim)));
  if (yenileDugmesi) ek.push(oge("button", { type: "button" }, metin("yenile")));
  if (notMetni) ek.push(oge("p", { class: "rozet-not" }, metin(notMetni)));
  return cekirdek({ baslik, deger, birim }, ...ek);
}

// (b) Yuva tabanli bilesim: bilesen deligi birakir, doldurmayi cagirana birakir.
const rozetYuvali = ({ baslik, deger, birim, ek = [] }) => cekirdek({ baslik, deger, birim }, ...ek);

// Iki yaklasimin ayni girdi icin urettigi agaclari karsilastir.
const yaz = (d, girinti = 0) => {
  const satir = d.metin !== undefined
    ? `${"  ".repeat(girinti)}"${d.metin}"`
    : `${"  ".repeat(girinti)}${d.ad}${d.ozn.class ? "." + d.ozn.class : ""}`;
  return [satir, ...d.cocuklar.flatMap((c) => yaz(c, girinti + 1))];
};

const sarmalanan = rozetSarmalayanV2({
  baslik: "Sıcaklık", deger: -4.2, birim: "°C",
  esikAsildi: true, kaynakGoster: true, kaynak: "istasyon-3",
  egilim: null, yenileDugmesi: false, notMetni: null,
});

const yuvali = rozetYuvali({
  baslik: "Sıcaklık", deger: -4.2, birim: "°C",
  ek: [
    oge("span", { class: "rozet-uyari" }, metin("esik asildi")),
    oge("small", { class: "rozet-kaynak" }, metin("istasyon-3")),
  ],
});

console.log("sarmalanan agac:");
console.log(yaz(sarmalanan).join("\n"));
console.log("\nyuvali agac:");
console.log(yaz(yuvali).join("\n"));
console.log("\nagaclar ayni mi:", JSON.stringify(sarmalanan) === JSON.stringify(yuvali));

// Olcum: ihtiyac sayisi arttikca iki yaklasimin yuzeyi nasil buyuyor?
const govde = (f) => f.toString().split("\n").length;
const mantiksal = (f) => (f.toString().match(/\bif \(/g) ?? []).length;
console.log("\nyaklasim                 gövde satırı  dallanma  çağıran tarafın seçenekleri");
for (const [ad, f, ihtiyac] of [
  ["sarmalayan (2 ihtiyaç)", rozetSarmalayanV1, 2],
  ["sarmalayan (5 ihtiyaç)", rozetSarmalayanV2, 5],
  ["yuva tabanlı", rozetYuvali, 0],
]) {
  console.log(
    `${ad.padEnd(24)} ${String(govde(f)).padStart(12)} ${String(mantiksal(f)).padStart(9)} ` +
      `${(ihtiyac ? 2 ** ihtiyac : "sınırsız").toString().padStart(28)}`
  );
}
```

```
sarmalanan agac:
div.rozet
  span.rozet-baslik
    "Sıcaklık"
  output.rozet-deger
    "-4.2 °C"
  span.rozet-uyari
    "esik asildi"
  small.rozet-kaynak
    "istasyon-3"

yuvali agac:
div.rozet
  span.rozet-baslik
    "Sıcaklık"
  output.rozet-deger
    "-4.2 °C"
  span.rozet-uyari
    "esik asildi"
  small.rozet-kaynak
    "istasyon-3"

agaclar ayni mi: true

yaklasim                 gövde satırı  dallanma  çağıran tarafın seçenekleri
sarmalayan (2 ihtiyaç)              6         2                            4
sarmalayan (5 ihtiyaç)             10         5                           32
yuva tabanlı                        1         0                     sınırsız
```

İki ağaç birebir aynı. Verilen bir durumda hangi kalıbın kullanıldığı çıktıdan anlaşılmaz;
fark yalnızca kaynak metinde ve değişim maliyetindedir.

Tablo bu maliyeti veriyor. Beş mantıksal özellikli sarmalayan bileşen 32 ayrı özellik
birleşimi tanımlar. Bu birleşimlerin tümü anlamlı değildir — yenileme düğmesi ile not
satırı bir arada belki hiç istenmez — ama bileşen hepsini kabul eder ve hiçbirini
sınamamıştır. Beş dallanma, beş özelliğin birbirini nasıl etkilediğine dair beş sessiz
karardır: eklenme sırası sabittir, çağıran değiştiremez.

Yuva tabanlı sürümde gövde tek satırdır ve dallanma yoktur. Çağıranın seçenekleri
sayılamaz, çünkü çağıran istediği ağacı verebilir. Bileşen bu ağaç hakkında hiçbir varsayım
yapmaz; yalnızca çekirdeğin sonuna ekler.

Asıl ayrım altıncı istekte görünür. Sarmalayan kalıpta altıncı istek bileşenin gövdesini
yeniden açar: yeni bir özellik, yeni bir dallanma, yeniden gözden geçirilecek bir dosya.
Yuva tabanlı kalıpta bileşene dokunulmaz; yeni düğüm çağıran tarafta kurulur.

## Özellik Zinciri

Seçenek patlaması bileşenin kendi gövdesinde birikir. İkinci maliyet ise ağaç boyunca
yayılır: bir değeri kullanan bileşen, o değeri üreten bileşenin uzağındaysa aradaki her
katman değeri taşımak zorundadır. Buna **özellik zinciri (prop drilling)** denir.

Ölçüm tablosunda birim sistemi tercihini sayfa düzeyi biliyor, biçimlendirmeyi ise hücre
yapıyor. Arada tablo, gövde ve satır var.

```js
// ozellik-zinciri.mjs — ara katmanlarin yalnizca tasidigi ozelliklerin sayilmasi
const oge = (ad, ozn = {}, ...cocuklar) => ({ ad, ozn, cocuklar: cocuklar.flat().filter(Boolean) });
const metin = (deger) => ({ ad: "#metin", ozn: {}, cocuklar: [], metin: deger });
const bicim = (c, sistem) => (sistem === "si" ? `${c.toFixed(1)} °C` : `${(c * 1.8 + 32).toFixed(1)} °F`);

// Her bilesen aldigi ozellikleri ve bunlarin kacini kendisi kullandigini bildirir.
const defter = [];
const kaydet = (ad, alinan, kullanilan) =>
  defter.push({ ad, alinan, kullanilan, tasinan: alinan.filter((a) => !kullanilan.includes(a)) });

// (a) Zincirli akis: birim sistemi ust katmandan en alta kadar her imzada yeniden yazilir.
function zDeger({ santigrat, birimSistemi }) {
  kaydet("Değer", ["santigrat", "birimSistemi"], ["santigrat", "birimSistemi"]);
  return oge("output", {}, metin(bicim(santigrat, birimSistemi)));
}
function zSatir({ baslik, santigrat, birimSistemi }) {
  kaydet("Satır", ["baslik", "santigrat", "birimSistemi"], ["baslik"]);
  return oge("tr", {}, oge("th", {}, metin(baslik)), oge("td", {}, zDeger({ santigrat, birimSistemi })));
}
function zGovde({ olcumler, birimSistemi }) {
  kaydet("Gövde", ["olcumler", "birimSistemi"], ["olcumler"]);
  return oge("tbody", {}, ...olcumler.map((o) => zSatir({ ...o, birimSistemi })));
}
function zTablo({ baslik, olcumler, birimSistemi }) {
  kaydet("Tablo", ["baslik", "olcumler", "birimSistemi"], ["baslik"]);
  return oge("table", {}, oge("caption", {}, metin(baslik)), zGovde({ olcumler, birimSistemi }));
}

// (b) Yuva tabanli akis: deger dugumu, birim sisteminin bilindigi yerde kurulur;
// ara katmanlar hazir dugumu tasir, veriyi degil.
function yDeger({ santigrat, birimSistemi }) {
  kaydet("Değer/yuva", ["santigrat", "birimSistemi"], ["santigrat", "birimSistemi"]);
  return oge("output", {}, metin(bicim(santigrat, birimSistemi)));
}
function ySatir({ baslik, hucre }) {
  kaydet("Satır/yuva", ["baslik", "hucre"], ["baslik", "hucre"]);
  return oge("tr", {}, oge("th", {}, metin(baslik)), oge("td", {}, hucre));
}
function yGovde({ satirlar }) {
  kaydet("Gövde/yuva", ["satirlar"], ["satirlar"]);
  return oge("tbody", {}, ...satirlar);
}
function yTablo({ baslik, govde }) {
  kaydet("Tablo/yuva", ["baslik", "govde"], ["baslik", "govde"]);
  return oge("table", {}, oge("caption", {}, metin(baslik)), govde);
}

const olcumler = [{ baslik: "Üst yamaç", santigrat: -4.2 }, { baslik: "Alt yamaç", santigrat: 1.6 }];
const sistem = "imperyal";

const zincirli = zTablo({ baslik: "Kuzey Yamaç", olcumler, birimSistemi: sistem });
const yuvali = yTablo({
  baslik: "Kuzey Yamaç",
  govde: yGovde({
    satirlar: olcumler.map((o) =>
      ySatir({ baslik: o.baslik, hucre: yDeger({ santigrat: o.santigrat, birimSistemi: sistem }) })),
  }),
});

const yaz = (d, g = 0) => [
  d.metin !== undefined ? `${"  ".repeat(g)}"${d.metin}"` : `${"  ".repeat(g)}${d.ad}`,
  ...d.cocuklar.flatMap((c) => yaz(c, g + 1)),
];
console.log("zincirli akışın ürettiği ağaç:");
console.log(yaz(zincirli).join("\n"));
console.log("iki ağaç aynı mı:", JSON.stringify(zincirli) === JSON.stringify(yuvali));

const ozet = new Map();
for (const k of defter) ozet.set(k.ad, k);
console.log("\nbileşen       aldığı  kullandığı  yalnızca taşıdığı");
for (const [ad, k] of ozet)
  console.log(`${ad.padEnd(13)} ${String(k.alinan.length).padStart(6)} ${String(k.kullanilan.length).padStart(11)}  ${k.tasinan.join(", ") || "-"}`);

const topla = (ek) => [...ozet.values()].filter((k) => k.ad.includes("/yuva") === ek).reduce((t, k) => t + k.tasinan.length, 0);
console.log(`\nzincirli akışta yalnızca taşınan özellik sayısı: ${topla(false)}`);
console.log(`yuva tabanlı akışta yalnızca taşınan özellik sayısı: ${topla(true)}`);
```

```
zincirli akışın ürettiği ağaç:
table
  caption
    "Kuzey Yamaç"
  tbody
    tr
      th
        "Üst yamaç"
      td
        output
          "24.4 °F"
    tr
      th
        "Alt yamaç"
      td
        output
          "34.9 °F"
iki ağaç aynı mı: true

bileşen       aldığı  kullandığı  yalnızca taşıdığı
Tablo              3           1  olcumler, birimSistemi
Gövde              2           1  birimSistemi
Satır              3           1  santigrat, birimSistemi
Değer              2           2  -
Değer/yuva         2           2  -
Satır/yuva         2           2  -
Gövde/yuva         1           1  -
Tablo/yuva         2           2  -

zincirli akışta yalnızca taşınan özellik sayısı: 5
yuva tabanlı akışta yalnızca taşınan özellik sayısı: 0
```

Zincirli akışta üç ara katmanın hiçbiri birim sistemini kullanmıyor; üçü de yalnızca
aşağıya geçiriyor. Sayı beş, çünkü ölçüm verisi de aynı yolu izliyor. Yuva tabanlı akışta
bu sayı sıfır: değer düğümü, birim sisteminin zaten bilindiği yerde kuruluyor ve ara
katmanlar hazır düğümü taşıyor.

Zincirin gerçek bedeli imzalarda değil, bağımlılıktadır. Satır bileşeni birim sistemini
imzasında taşıdığı için, birim sisteminin varlığından haberdar olmuş olur. Bu özellik
kaldırıldığında ya da adı değiştiğinde, onu hiç kullanmayan üç bileşen de değişmek
zorundadır. Yuva tabanlı akışta satır bileşeni bir hücre alır; hücrenin neye göre
biçimlendirildiğini bilmez ve bilmediği şey değiştiğinde etkilenmez.

Bu, Bağlam Aktarımı dersindeki mekanizmanın neden var olduğunu da açıklar. Bağlam, zinciri
kesmenin ikinci yoludur: değer ağacın bir noktasında sağlanır, isteyen düğüm doğrudan okur.
Yuva tabanlı bileşim ile bağlam birbirinin yerine geçmez — biri **yapıyı**, diğeri
**veriyi** aşağı taşır. Ölçüm tablosunda hücrenin nasıl görüneceği bir yapı kararıdır ve
yuvaya aittir; birim sistemi tercihi ise sayfanın her yerinde okunan bir veridir ve bağlama
aittir.

## Kalıtım Yerine Bileşim

Sarmalama kalıbının ucundaki bir uygulama, bileşenleri kalıtımla türetmektir: temel rozet
sınıfı, ondan türeyen uyarı rozeti, ondan türeyen eğilimli uyarı rozeti. Bu yol arayüz
ağaçlarında iki nedenle tıkanır.

Birincisi, kalıtım tek eksenlidir. Uyarı gösteren rozetle kaynağı gösteren rozet ayrı
dallardaysa, ikisini birden isteyen üçüncü bir rozet için ortak bir ata yoktur; her yeni
birleşim yeni bir sınıf ister. Beş bağımsız istek 32 sınıfa çıkar. Yuva tabanlı bileşimde
aynı 32 birleşim tek bileşenin 32 farklı çağrısıdır.

İkincisi, kalıtım gövdenin içine erişim verir; bileşim vermez. Türeyen sınıf atasının iç
yapısına yaslanır, ata değişince türeyen kırılır. Bileşimde bileşenin dışarıya söz verdiği
tek şey özellik yüzeyidir; iç yapısı sözleşmenin parçası değildir.

## Sarmalama Ne Zaman Doğrudur

Yuva tabanlı bileşimin üstünlüğü koşulsuz değildir. Sarmalama, bileşenin **kararı sahiplenmesi**
gerektiği yerde doğrudur.

Süzgeç panelindeki eşik alanı buna örnektir. Alanın etiketi, hata iletisi ve geçersizlik
bildirimi arasındaki ilişki sabit olmalıdır: etiket alana bağlanmalı, hata iletisi alana
ek açıklama olarak iliştirilmeli, geçersizlik durumu her ikisine de yansımalıdır. Bu ilişki
çağırana bırakılırsa her çağrıda yeniden kurulur ve bir yerde unutulur. Bileşen burada
deliği bırakmaz; yapıyı kendi içinde kilitler ve dışarıya yalnızca etiket metniyle hata
iletisini alan bir yüzey sunar.

Ölçüt şudur: yapı **doğruluk** taşıyorsa sarmalanır, yalnızca **görünüm** taşıyorsa yuvaya
bırakılır. Rozetin sonuna ne eklendiği bir görünüm kararıdır; etiketin alana nasıl
bağlandığı bir doğruluk kararıdır. Bir bileşende ikisi bir arada bulunabilir: rozet
çekirdeği kilitli, sonu açıktır.

## Özet

- Bileşimin iki kalıbı vardır: sarmalayan bileşen yapıyı içeride sabitler, yuva tabanlı
  bileşim yapının bir bölümünü çağırandan alır.
- İki kalıp aynı ağacı üretebilir; ayrım çıktıda değil, yeni bir istek geldiğinde hangi
  dosyanın açıldığındadır.
- Mantıksal özelliklerle kurulan sarmalayan bileşende seçenek sayısı üstel büyür; beş
  bağımsız istek 32 birleşim ve beş dallanma demektir.
- Özellik zinciri, ara katmanların kullanmadığı özellikleri taşımasıdır; ölçüsü "yalnızca
  taşınan özellik" sayısıdır ve yuva tabanlı bileşimde sıfıra iner.
- Yuva yapıyı, bağlam veriyi aşağı taşır; ikisi birbirinin yerine geçmez.
- Doğruluk taşıyan yapı sarmalanır, yalnızca görünüm taşıyan yapı yuvaya bırakılır.

## Sonraki Adım

Bu ders yapının yeniden kullanımını çözdü: aynı ağacı farklı içeriklerle kurmanın yolu
belli. Ancak bileşenlerde yeniden kullanılan tek şey yapı değildir. Süzgeç panelindeki
arama alanı girdiyi geciktirerek tetikliyor, ölçüm tablosu sıralama tercihini adres
çubuğuyla eşitliyor, rozet aralıklı olarak yenileniyor. Üçünün de içinde durum, yan etki ve
temizlik var; üçü de birbirinden bağımsız yazılmış ve üçü de aynı hataları tekrar ediyor.
Bu mantık bir bileşene bağlı olduğu sürece taşınamaz. Sonraki ders, durumu ve yan etkiyi
işaretleme üretmeden paketleyen birimi kurar ve bu birimlerin birbirine eklenmesinin hangi
kurala bağlı olduğunu gösterir.
