Ders 11 / 25
Bağlam Aktarımı
Bir değeri ağaçta sağlayıp aşağıdaki herhangi bir düğümde okumak; özellik zincirinin sorunu, sağlayıcının yukarı doğru çözümlenmesi, en yakın sağlayıcının gölgelemesi, sağlanan değerin kimliğinin tüketici sayısına etkisi ve bağlamın uygun olmadığı yerler.
İçindekiler
Önceki dersin üç saklama biçimi de tek bir bileşenin içinde kalır. Değerin başka bir bileşene ulaşması için bilinen tek yol vardır: üstten alta doğru özellik olarak verilmek. Ölçüm istasyonu sayfasında bu yol uzar. Sıcaklığın santigrat mı fahrenhayt mı gösterileceği sayfanın en üstünde seçilir; bu bilgiye ihtiyaç duyan yer en altta, tablo satırının içindeki ölçüm rozetidir. Aradaki dört bileşen — sayfa gövdesi, ölçüm tablosu, tablo satırı, hücre — birimi hiç kullanmaz, yalnız taşır.
Bu ders zinciri kısaltan mekanizmayı kurar: değeri ağacın bir düğümünde sağlamak ve altındaki herhangi bir düğümde, aradakilere hiç dokunmadan okumak.
Özellik Zincirinin Sorunu
Bir değerin ara bileşenlerden geçirilerek taşınmasına özellik zinciri (prop drilling) denir. Zincirin kendisi bir hata değildir; iki üç düzey için en açık çözüm budur. Uzadıkça üç ayrı maliyet üretir.
Birincisi arayüz genişlemesidir. Ölçüm tablosunun API’sinde artık bir birim parametresi vardır, oysa tablo birimle hiç ilgilenmez. Bileşenin dışarıdan görünen sözleşmesi, kendi işini anlatmayan alanlarla dolar.
İkincisi değişim maliyetidir. Zincire yeni bir değer eklemek — yerel ayar, ondalık basamak sayısı, eşik renkleri — aradaki her bileşende bir imza değişikliği demektir. Beş düzeyli bir zincire üç değer eklemek on beş dosyaya dokunmaktır.
Üçüncüsü yeniden kullanımdır. Birimi taşımak zorunda olan bir tablo, birimin olmadığı bir sayfada kullanılamaz; parametre isteğe bağlı yapıldığında ise varsayılanın nereden geleceği sorusu doğar.
Sağlayıcı ve Çözümleme
Bağlam bu üç maliyeti ortadan kaldırır. Ağacın bir düğümü bir anahtar altında değer sağlar; o düğümün altındaki herhangi bir bileşen aynı anahtarla değeri okur. Aradaki bileşenlerin haberi olmaz.
Okuma bir arama işlemidir: bileşen kendi düğümünden başlar, ata zinciri boyunca yukarı çıkar ve o anahtarı sağlayan ilk düğümde durur. Hiçbir düğüm sağlamıyorsa bağlamın tanımıyla birlikte verilen varsayılan değer kullanılır.
// baglam-cozumleme.mjs — saglayicinin agacta yukari dogru aranmasi const dugum = (ad, saglanan, cocuklar = []) => { const d = { ad, saglanan, cocuklar, ust: null }; for (const c of cocuklar) c.ust = d; return d; }; const VARSAYILAN = { birim: "kelvin" }; // hicbir saglayici yoksa kullanilir function coz(baslangic, anahtar) { let d = baslangic; let adim = 0; while (d) { if (d.saglanan && anahtar in d.saglanan) return { deger: d.saglanan[anahtar], saglayici: d.ad, adim }; d = d.ust; adim++; } return { deger: VARSAYILAN[anahtar], saglayici: "(varsayilan)", adim }; } const rozet1 = dugum("rozet-1"); const rozet2 = dugum("rozet-2"); const rozet3 = dugum("rozet-3"); const sayfa = dugum("sayfa", { birim: "santigrat" }, [ dugum("baslik"), dugum("suzgec-paneli", null, [dugum("suzgec-listesi", null, [rozet3])]), dugum("olcum-tablosu", null, [ dugum("satir-1", null, [rozet1]), dugum("karsilastirma-panosu", { birim: "fahrenhayt" }, [rozet2]), ]), ]); const ayrikRozet = dugum("ayrik-rozet"); // agacin disinda console.log(`kok: ${sayfa.ad}`); for (const d of [rozet1, rozet2, rozet3, ayrikRozet]) { const s = coz(d, "birim"); console.log( ` ${d.ad.padEnd(12)} birim=${s.deger.padEnd(10)}`, `kaynak=${s.saglayici.padEnd(21)} ${s.adim} ust dugum tarandi`, ); }
kok: sayfa rozet-1 birim=santigrat kaynak=sayfa 3 ust dugum tarandi rozet-2 birim=fahrenhayt kaynak=karsilastirma-panosu 1 ust dugum tarandi rozet-3 birim=santigrat kaynak=sayfa 3 ust dugum tarandi ayrik-rozet birim=kelvin kaynak=(varsayilan) 1 ust dugum tarandi
Dört satır dört ayrı davranışı gösterir. Birinci rozet üç düzey yukarıdaki sayfa sağlayıcısını bulmuştur; aradaki tablo ve satır bileşenleri birimi hiç görmemiştir.
İkinci rozet karşılaştırma panosunun içindedir ve bir düzey yukarıdaki sağlayıcıda durur. Sayfa sağlayıcısı hâlâ oradadır, ama aranmaz: en yakın sağlayıcı kazanır. Bu, aynı sayfada bir bölümün farklı bir birimle gösterilmesini olanaklı kılar.
Üçüncü rozet ağacın bambaşka bir dalındadır ve yine sayfa sağlayıcısını bulur. Bağlam bir dala değil, bir alt ağaca yayılır.
Dördüncü rozet hiçbir sağlayıcının altında değildir ve varsayılana düşer. Varsayılanın anlamlı seçilmesi bir tasarım işidir: bağlam olmadan da çalışan bir bileşen, tek başına sınanabilir ve başka bir sayfada yeniden kullanılabilir.
Bağlam Sözcüksel Değil, Konumsaldır
Bu mekanizmanın en çok yanlış anlaşılan yanı, benzediği şeyden ayrıldığı noktadır. Programlama Temelleri kursundaki kapsam sözcükseldir: bir işlevin gördüğü değişkenler, o işlevin kaynak kodda nerede yazıldığına bağlıdır. Bağlam ise konumsaldır: bir bileşenin gördüğü değer, o bileşenin ağaçta nereye yerleştirildiğine bağlıdır.
Aynı ölçüm rozeti kaynakta bir kez yazılır; tablonun içinde santigrat, karşılaştırma panosunun içinde fahrenhayt okur. Kaynak kod değişmemiştir, yer değişmiştir.
En yakın sağlayıcının kazanması, aynı kursta tanımlanan gölgelemenin ağaç üzerindeki karşılığıdır: iç sağlayıcı, dıştakini kendi alt ağacında görünmez kılar. Bu güç bir maliyetle gelir. Bir bileşenin hangi değeri okuyacağını anlamak için tanımına bakmak yetmez; ağaçtaki yerini bilmek gerekir. Bu yüzden bağlamla taşınan değerler az sayıda ve adları açık olmalıdır.
Değişimin Maliyeti
Sağlanan değer değiştiğinde, o bağlamı okuyan bütün bileşenler yeniden çizilir — ağaçta nerede olurlarsa olsunlar, aradaki bileşenler değişmemiş olsa bile. Sağlanan değerin kimliği bu yüzden doğrudan bir maliyet kalemidir.
// baglam-maliyeti.mjs — saglanan degerin kimliginin tuketici sayisina etkisi const BIRIM_TUKETICI = 6; // birimi okuyan bilesen sayisi const SATIR_TUKETICI = 2; // secili satiri okuyan bilesen sayisi const OLAYLAR = [ { ad: "panel acildi", birim: "santigrat", secili: null }, { ad: "satir 1 secildi", birim: "santigrat", secili: 1 }, { ad: "satir 2 secildi", birim: "santigrat", secili: 2 }, { ad: "birim degisti", birim: "fahrenhayt", secili: 2 }, ]; function calistir(strateji) { let oncekiBirim = "santigrat"; // ilk olusturmada kurulan degerler let oncekiSecili = null; let toplam = 0; console.log(`${strateji}:`); for (const olay of OLAYLAR) { let sayi = 0; if (strateji === "govdede kurulan nesne") { sayi = BIRIM_TUKETICI + SATIR_TUKETICI; // kimlik her olusturmada degisir } else if (strateji === "bellenmis tek baglam") { const degisti = olay.birim !== oncekiBirim || olay.secili !== oncekiSecili; sayi = degisti ? BIRIM_TUKETICI + SATIR_TUKETICI : 0; } else { if (olay.birim !== oncekiBirim) sayi += BIRIM_TUKETICI; if (olay.secili !== oncekiSecili) sayi += SATIR_TUKETICI; } oncekiBirim = olay.birim; oncekiSecili = olay.secili; toplam += sayi; console.log(` ${olay.ad.padEnd(15)} -> yeniden cizilen tuketici: ${sayi}`); } console.log(` toplam: ${toplam}`); } console.log(`${BIRIM_TUKETICI} birim tuketicisi, ${SATIR_TUKETICI} satir tuketicisi, 4 olay`); for (const s of ["govdede kurulan nesne", "bellenmis tek baglam", "iki ayri baglam"]) calistir(s);
6 birim tuketicisi, 2 satir tuketicisi, 4 olay govdede kurulan nesne: panel acildi -> yeniden cizilen tuketici: 8 satir 1 secildi -> yeniden cizilen tuketici: 8 satir 2 secildi -> yeniden cizilen tuketici: 8 birim degisti -> yeniden cizilen tuketici: 8 toplam: 32 bellenmis tek baglam: panel acildi -> yeniden cizilen tuketici: 0 satir 1 secildi -> yeniden cizilen tuketici: 8 satir 2 secildi -> yeniden cizilen tuketici: 8 birim degisti -> yeniden cizilen tuketici: 8 toplam: 24 iki ayri baglam: panel acildi -> yeniden cizilen tuketici: 0 satir 1 secildi -> yeniden cizilen tuketici: 2 satir 2 secildi -> yeniden cizilen tuketici: 2 birim degisti -> yeniden cizilen tuketici: 6 toplam: 10
Birinci strateji, sağlanan değeri sağlayıcının gövdesinde her oluşturmada yeniden kuran yaygın yazımdır. Değerin içeriği değişmese bile kimliği değişir, dolayısıyla panelin açılması bile sekiz tüketiciyi yeniden çizer. Bu, önceki derste kurulan kimlik kararlılığı sorununun bağlamdaki karşılığıdır ve çözümü aynıdır: sağlanan değer bellenir.
İkinci strateji bunu yapar ve ilgisiz oluşturmaları eler; otuz iki tüketici oluşturması yirmi dörde iner. Ama seçili satır her değiştiğinde birimi okuyan altı bileşen de yeniden oluşturulur, çünkü ikisi tek bir nesnede taşınmaktadır.
Üçüncü strateji değerleri ayırır: seyrek değişen birim bir bağlamda, sık değişen seçim başka bir bağlamda. Toplam ona iner. Kural buradan çıkar: bir bağlamda birlikte taşınan değerler aynı sıklıkta değişmelidir. Değişim sıklıkları ayrışıyorsa bağlam bölünür.
Bağlamın Uygun Olmadığı Yerler
Bağlam bir durum yönetimi çözümü değildir; bir taşıma yoludur. Değer yine bir yerde durum olarak tutulur, bağlam yalnız onun ağaçta dolaşmasını sağlar.
Uygun olduğu değerler ortak bir özellik taşır: seyrek değişirler ve ağacın geniş bir bölümünü ilgilendirirler. Görsel tema, ölçü birimi, yerel ayar, oturum açmış kullanıcı bilgisi, biçim ayarları, erişilebilirlik tercihleri bu tanıma uyar.
Uygun olmadığı yerler de bellidir. Sık değişen bir liste — kaydırma konumu, imleç altındaki satır, bir animasyonun ilerleme değeri — bağlamla taşındığında her değişimde bütün tüketicileri yeniden çizer. İki bileşen arasında paylaşılan tek bir değer için bağlam kurmak, önceki dersteki durumun yukarı taşınmasından daha karmaşık ve daha maliyetlidir.
Son bir ölçüt sınanabilirliktir. Bağlam okuyan bir bileşen tek başına oluşturulduğunda varsayılan değere düşer. Varsayılan anlamlıysa bileşen bağımsız olarak sınanabilir; varsayılan yoksa ve bağlamın bulunmaması hata üretiyorsa, bileşen her sınamada bir sağlayıcıyla sarmalanmak zorunda kalır.
Özet
- Özellik zinciri uzadıkça ara bileşenlerin arayüzünü genişletir, değişim maliyetini artırır ve yeniden kullanımı zorlaştırır.
- Bağlam okuma, tüketici düğümden ata zinciri boyunca yukarı çıkıp o anahtarı sağlayan ilk düğümde duran bir aramadır; hiçbiri yoksa varsayılan kullanılır.
- En yakın sağlayıcı kazanır; iç sağlayıcı dıştakini kendi alt ağacında gölgeler.
- Bağlam sözcüksel değil konumsaldır: bileşenin gördüğü değer, tanımının yerine değil ağaçtaki konumuna bağlıdır.
- Sağlanan değer her oluşturmada yeniden kurulursa bütün tüketiciler her oluşturmada yeniden çizilir; değer bellenir.
- Bir bağlamda birlikte taşınan değerler aynı sıklıkta değişmelidir; sıklıklar ayrışıyorsa bağlam bölünür.
Sonraki Adım
Bağlam bir değeri ağaçta aşağı doğru akıtır. Ters yönde akan bir şey daha vardır ve bu derse kadar hiç ele alınmadı: hata. Ölçüm tablosunun bir satırı, sunucudan gelen bozuk bir kayıt yüzünden oluşturma sırasında bir istisna atarsa ne olur? Bildirimsel bir ağaçta bu sorunun yanıtı sanıldığından serttir: yarım kalmış bir ağaç tutarsızdır ve çalışma zamanının elinde onu kurtaracak bir bilgi yoktur. Sonraki ders bu davranışın gerekçesini, bir alt ağacın hatasını çevresinden yalıtan mekanizmayı ve bu mekanizmanın yakalayamadığı hata türlerini ele alır.
İlerlemeni kaydetmek ve not almak için Giriş yap
Notlarım
Not almak için giriş yapmalısın.