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

# Sunum ve Konteyner Ayrımı

Veriyi getiren sorumlulukla görünümü üreten sorumluluğun ayrılması; ayrımın sahte bağımlılık sayısıyla ölçülmesi, tek sunum bileşeninin iki konteynerle kullanılması ve ayrımın aşırıya kaçtığı yer.

Ölçüm tablosu şu anda dört iş yapıyor: ölçümleri ağdan getiriyor, kullanıcının sıralama
tercihini depolamadan okuyuyor, satırları sıralıyor ve bir tablo ağacı üretiyor. Dördü de
aynı işlevin gövdesinde.

Bu bileşenin boş tabloyla nasıl göründüğünü sınamak isteyen biri, önce sahte bir ağ
kaynağı kurmak zorundadır. Aynı tabloyu bir arşiv dosyasındaki ölçümlerle çizmek isteyen
biri, bileşenin içindeki ağ çağrısını değiştirmek zorundadır. İki istek de görünümle ilgili
değil, ama ikisi de veri katmanına çarpıyor.

## İki Sorumluluk

Ayrım şu iki rolü tanımlar.

**Sunum bileşeni (presentational component)** yalnızca aldığı özelliklerden bir ağaç üretir.
Ağa erişmez, saati okumaz, depolamaya bakmaz, üst kapsamdan değer almaz. Aynı özelliklerle
her zaman aynı ağacı verir; Programlama Temelleri kursunda tanımlanan saf fonksiyon tanımına
uyar.

**Konteyner bileşeni (container component)** veriyi elde eder, biçime sokar ve sunum
bileşenine özellik olarak verir. Kendisi işaretleme üretmez; ürettiği tek şey bir özellik
kümesidir. (Terim, düzen bağlamındaki esnek kapsayıcı ve ızgara kapsayıcısıyla karışmasın
diye "kapsayıcı" değil **konteyner** yazılır.)

Ayrımın kuralı tek cümleye iner: sunum bileşeninin girdisi imzasında **eksiksiz** yazılıdır.
İmzasında yazmayan hiçbir şeye bağlı değilse ayrım yapılmıştır.

## Ayrımın Ölçüsü

Kazanç, sınama için kurulması gereken sahte bağımlılık sayısıyla ölçülebilir.

```js
// ayrim.mjs — birlesik bilesen ile sunum/konteyner ayriminin sinanabilirlik farki
import { deepStrictEqual } from "node:assert";

const oge = (ad, ozn = {}, ...cocuklar) => ({ ad, ozn, cocuklar: cocuklar.flat().filter(Boolean) });
const metin = (deger) => ({ ad: "#metin", ozn: {}, cocuklar: [], metin: deger });

// --- Birlesik bilesen: veriyi de getirir, siralar, bicimler ve cizer ---
async function tabloBirlesik({ kaynak, saat, depo }) {
  const alan = depo.oku("siralama") ?? "ad";
  const ham = await kaynak.getir();                      // ag
  const satirlar = [...ham].sort((a, b) => (a[alan] > b[alan] ? 1 : -1));
  const damga = new Date(saat.simdi()).toISOString();    // zaman
  return oge("table", {},
    oge("caption", {}, metin(`Kuzey Yamaç — ${damga}`)),
    oge("tbody", {}, ...satirlar.map((s) =>
      oge("tr", { "data-ad": s.ad },
        oge("th", {}, metin(s.ad)),
        oge("td", {}, metin(`${s.deger.toFixed(1)} °C`))))));
}

// --- Ayrilmis surum ---
// Sunum bileseni: yalnizca ozelliklerinden agac uretir. Ag yok, zaman yok, depolama yok.
const tabloGorunumu = ({ baslik, damga, satirlar }) =>
  oge("table", {},
    oge("caption", {}, metin(`${baslik} — ${damga}`)),
    oge("tbody", {}, ...satirlar.map((s) =>
      oge("tr", { "data-ad": s.ad },
        oge("th", {}, metin(s.ad)),
        oge("td", {}, metin(`${s.deger.toFixed(1)} °C`))))));

// Konteyner 1: canli olcum kaynagi.
async function canliKonteyner({ kaynak, saat, depo }) {
  const alan = depo.oku("siralama") ?? "ad";
  const ham = await kaynak.getir();
  return tabloGorunumu({
    baslik: "Kuzey Yamaç",
    damga: new Date(saat.simdi()).toISOString(),
    satirlar: [...ham].sort((a, b) => (a[alan] > b[alan] ? 1 : -1)),
  });
}

// Konteyner 2: arsiv dosyasindan okunan ayni bicimdeki veri.
function arsivKonteyneri({ arsivSatirlari, damga }) {
  return tabloGorunumu({
    baslik: "Kuzey Yamaç",
    damga,
    satirlar: [...arsivSatirlari].sort((a, b) => (a.ad > b.ad ? 1 : -1)),
  });
}

// --- Sinama: kac sahte bagimlilik gerekiyor? ---
const OLCUMLER = [{ ad: "Üst yamaç", deger: -4.2 }, { ad: "Alt yamaç", deger: 1.63 }];
const DAMGA = "2026-02-11T06:00:00.000Z";

let sahte = 0;
const sahteKaynak = (v) => { sahte++; return { getir: async () => v }; };
const sahteSaat = (t) => { sahte++; return { simdi: () => t }; };
const sahteDepo = (d) => { sahte++; return { oku: (a) => d[a] }; };

sahte = 0;
const birlesikAgac = await tabloBirlesik({
  kaynak: sahteKaynak(OLCUMLER), saat: sahteSaat(Date.parse(DAMGA)), depo: sahteDepo({ siralama: "ad" }),
});
const birlesikSahte = sahte;

sahte = 0;
const gorunumAgaci = tabloGorunumu({
  baslik: "Kuzey Yamaç", damga: DAMGA,
  satirlar: [{ ad: "Alt yamaç", deger: 1.63 }, { ad: "Üst yamaç", deger: -4.2 }],
});
const gorunumSahte = sahte;

deepStrictEqual(birlesikAgac, gorunumAgaci);
console.log("birleşik bileşenin ağacı ile sunum bileşeninin ağacı aynı: evet");
console.log(`sınama için gereken sahte bağımlılık — birleşik: ${birlesikSahte}, sunum: ${gorunumSahte}`);
console.log(`sınamanın eşzamansız olması gerekiyor mu — birleşik: evet, sunum: hayır`);

// Saflik: ayni ozelliklerle iki cagri ayni agaci verir.
const a = tabloGorunumu({ baslik: "Kuzey Yamaç", damga: DAMGA, satirlar: OLCUMLER });
const b = tabloGorunumu({ baslik: "Kuzey Yamaç", damga: DAMGA, satirlar: OLCUMLER });
deepStrictEqual(a, b);
console.log("sunum bileşeni aynı özelliklerle aynı ağacı üretiyor: evet");

// Iki konteyner, tek sunum bileseni.
sahte = 0;
const canli = await canliKonteyner({
  kaynak: sahteKaynak(OLCUMLER), saat: sahteSaat(Date.parse(DAMGA)), depo: sahteDepo({}),
});
const canliSahte = sahte;
sahte = 0;
const arsiv = arsivKonteyneri({ arsivSatirlari: OLCUMLER, damga: DAMGA });
const arsivSahte = sahte;
deepStrictEqual(canli, arsiv);
console.log(`\niki konteynerin ürettiği ağaç aynı: evet (canlı sahte=${canliSahte}, arşiv sahte=${arsivSahte})`);

// Gorunum durumlarinin es zamanli sayilabilirligi
const durumlar = [
  ["dolu tablo", { baslik: "Kuzey Yamaç", damga: DAMGA, satirlar: OLCUMLER }],
  ["tek satır", { baslik: "Kuzey Yamaç", damga: DAMGA, satirlar: [OLCUMLER[0]] }],
  ["boş tablo", { baslik: "Kuzey Yamaç", damga: DAMGA, satirlar: [] }],
  ["negatif ve sıfır", { baslik: "Kuzey Yamaç", damga: DAMGA, satirlar: [{ ad: "Zirve", deger: -0.04 }] }],
];
console.log("\ndurum              satır  ilk hücre");
for (const [ad, ozellikler] of durumlar) {
  const agac = tabloGorunumu(ozellikler);
  const govde = agac.cocuklar[1];
  const ilk = govde.cocuklar[0]?.cocuklar[1].cocuklar[0].metin ?? "-";
  console.log(`${ad.padEnd(18)} ${String(govde.cocuklar.length).padStart(5)}  ${ilk}`);
}
```

```
birleşik bileşenin ağacı ile sunum bileşeninin ağacı aynı: evet
sınama için gereken sahte bağımlılık — birleşik: 3, sunum: 0
sınamanın eşzamansız olması gerekiyor mu — birleşik: evet, sunum: hayır
sunum bileşeni aynı özelliklerle aynı ağacı üretiyor: evet

iki konteynerin ürettiği ağaç aynı: evet (canlı sahte=3, arşiv sahte=0)

durum              satır  ilk hücre
dolu tablo             2  -4.2 °C
tek satır              1  -4.2 °C
boş tablo              0  -
negatif ve sıfır       1  -0.0 °C
```

Üç sahteye karşı sıfır. Birleşik bileşeni sınamak için ağ kaynağı, saat ve depolama taklit
edilmek zorunda; üçü de görünümle ilgisiz. Sunum bileşeni için hiçbiri gerekmiyor, çünkü
üçü de imzada bir özellik olarak duruyor.

Sahte sayısı tek kazanç değil. Birleşik bileşen eşzamansızdır; sınaması bir sözü beklemek
zorundadır ve zamanlamaya bağlı kırılganlık taşır. Sunum bileşeni eşzamanlıdır: çağrılır ve
sonucu incelenir.

## Konteyner Değişir, Görünüm Değişmez

İkinci bölüm ayrımın asıl kazancını gösteriyor. Canlı konteyner ağdan okuyor ve üç sahte
istiyor; arşiv konteyneri elindeki diziyi kullanıyor ve hiç sahte istemiyor. İkisinin
ürettiği ağaç birebir aynı.

Bu, aynı görünümün istasyon sayfasında canlı ölçümlerle, arşiv sayfasında geçmiş
ölçümlerle ve sunucuda önceden üretilen bir sayfada dosyadan okunan ölçümlerle
kullanılabilmesi demektir. Görünüm bileşeni bu üç bağlamın hiçbirini bilmez.

Kural şudur: konteyner **nereden** sorusunu, sunum bileşeni **nasıl görünür** sorusunu
yanıtlar. İki soru bağımsız değiştiği için iki bileşen de bağımsız değişir.

## Ayrımın Görünür Kıldığı

Son tablo, ayrımın sınama dışında da bir şey kazandırdığını gösteriyor. Dört görünüm
durumu ağ olmadan, saniyeler içinde ve yan yana üretildi. Dördüncüsünde bir kusur ortaya
çıktı: -0.04 santigrat derece, tek ondalığa yuvarlanınca `-0.0 °C` oluyor.

Bu, Arayüz Tasarımının Temelleri kursundaki İşlevsel Renkler ve mikro metin tartışmalarının
somut bir örneğidir: negatif işareti taşıyan bir sıfır, okuyucuya sıcaklığın donma
noktasının altında olduğunu söyler; oysa değer neredeyse tam sıfırdır. Kusur bir
biçimlendirme kararıdır ve ağ katmanıyla hiç ilgisi yoktur — ama birleşik bileşende ancak
sahte bir kaynak kurup uygun veriyi ona yerleştirerek görülebilirdi.

Görünüm durumlarının ucuz üretilebilmesi, tasarım tarafındaki durum tablosunun gerçekten
denetlenebilmesi anlamına gelir. Arayüz Tasarımının Temelleri kursundaki Bileşen Durumları
konusunda tanımlanan beş etkileşim durumu, yükleme
ve boş durumlar, hata durumları — hepsi birer özellik kümesidir ve hepsi sıfır sahteyle
üretilebilir.

## Ayrım Nerede Karşılığını Vermez

Her bileşeni ikiye bölmek bir kazanç değildir.

Bir bileşenin hiç dış bağımlılığı yoksa zaten sunum bileşenidir; ona bir konteyner eklemek
yalnızca bir dosya ve bir dolaylılık katmanı ekler. Ölçüm rozeti buna örnektir: girdisi
zaten ölçümün adı, değeri ve eşiğidir.

Tersi de geçerlidir. Yalnızca tek bir yerde kullanılan, hiç yeniden kullanılmayacak bir
görünümü ayırmak, iki dosya arasında gidip gelmeyi zorunlu kılar ve okuma maliyetini
artırır. Ayrım, ikinci bir kullanım ya da sınanması gereken bir görünüm durumu ortaya
çıktığında karşılığını verir.

Üçüncü bir yanlış uygulama, ayrımın **dosya düzeyinde** yapılıp bağımlılığın kaçırılmasıdır.
Sunum bileşeni ayrı bir dosyada durup içinde saati okuyorsa ya da bir küresel değerden
biçim ayarını alıyorsa ayrım yapılmamıştır; sahte sayısı düşmez. Ölçü, dosya sayısı değil
imzanın eksiksizliğidir.

Ayrımın bir başka biçimi, konteynerin kendisinin bir bileşen bile olmamasıdır: önceki
derste kurulan özel kanca ya da birleştirilebilir işlev, veriyi elde etmeyi üstlenir
ve bileşen yalnızca onu çağırıp sonucu sunum bileşenine verir. Sorumluluk ayrımı aynıdır;
değişen, ayrımın hangi birimde yapıldığıdır.

## Özet

- Sunum bileşeni yalnızca özelliklerinden ağaç üretir; ağ, saat, depolama ve üst kapsam
  okumaz. Konteyner veriyi elde eder ve özellik kümesine çevirir.
- Ayrımın ölçüsü, sınama için kurulması gereken sahte bağımlılık sayısıdır; örnekte üçe
  karşı sıfır çıktı ve sunum bileşeninin sınaması eşzamanlı kaldı.
- Tek sunum bileşeni farklı konteynerlerle aynı ağacı üretir; canlı veri, arşiv verisi ve
  önceden üretilmiş sayfa aynı görünümü paylaşır.
- Görünüm durumlarının ucuz üretilebilmesi biçimlendirme kusurlarını ağ katmanına hiç
  dokunmadan görünür kılar.
- Dış bağımlılığı olmayan bileşene konteyner eklemek yalnızca dolaylılık ekler; ayrım
  ikinci kullanım ya da sınanacak durum ortaya çıktığında karşılığını verir.
- Ölçü dosya sayısı değil imzanın eksiksizliğidir; ayrı dosyadaki bir bileşen küresel değer
  okuyorsa ayrım yapılmamıştır.

## Sonraki Adım

Bu ders veriyi görünümden ayırdı, ama davranışı ayırmadı. Süzgeç panelindeki seçenek listesi
düşünüldüğünde geriye şu kalır: ok tuşlarıyla gezinme, ilk ve son ögeye atlama, harfe
basınca eşleşen ögeye gitme, seçim ve kapanma. Bu davranış her yerde aynıdır, ama listenin
görünümü her yerde farklıdır — bir yerde açılır liste, bir yerde yan panel, bir yerde etiket
kümesi. Davranışı bir bileşene gömmek, görünümü de onunla birlikte sabitlemek demektir.
Sonraki ders davranışı görünümden koparır ve bunun için gereken şeyin bir bileşen değil, saf
bir durum makinesi olduğunu gösterir.
