İçeriğe geç
academia.sh

Ders 02 / 22

İç İçe Rotalar ve Düzenler

Rotaların ağaç biçiminde tanımlanması; düzen bileşenleri ve alt görünüm yuvası, dizin rotası, eşleşmeden üretilen etkin düzen zinciri, gezinmede korunan kabuk ve parametre değişiminin ayrı ele alınması.

İçindekiler

Önceki dersin eşleyicisi düz bir tablo üzerinde çalıştı: her yol tek bir görünüme bağlandı. Kuzey Yamaç Ölçüm İstasyonu uygulamasının ekranları ise ortak bir kabuk paylaşıyor. İstasyon ayrıntısı ile ölçüm geçmişi aynı üst başlığı, aynı yan gezinmeyi ve aynı istasyon künyesini gösteriyor; yalnızca ortadaki bölge değişiyor.

Düz tabloyla bu ortak kabuk her rotanın bileşeninde yeniden kurulmak zorundadır. Sonucu üç ayrı kusurdur: aynı işaretleme birden çok yerde yinelenir, gezinmede kabuk yeniden çizilir, kabuğun içindeki durum — açık bir menü, kaydırılmış bir liste — her gezinmede sıfırlanır. Bu ders rotaları ağaç biçiminde tanımlayarak üçünü birden çözer.

Rota Ağacı

Adreslerin yolu zaten hiyerarşiktir. /istasyon/kuzey-yamac/olcum üç dilimden oluşur ve her dilim bir öncekinin içini daraltır. Rota tanımını da aynı biçimde iç içe yazmak mümkündür: her düğüm bir dilim üstlenir ve kendi altındaki düğümlere kalan dilimleri devreder.

Ağaçtaki düğümler iki işe yarar. Düzen bileşeni olan düğüm, kendi altındaki her görünümün çevresini kurar: başlık, gezinme, çerçeve. Yaprak düğüm ise ekranın değişen bölümünü doldurur. Düzen bileşeni, alt görünümün nereye yerleşeceğini bir alt görünüm yuvası ile bildirir. Bu, Web Bileşenleri konusundaki Şablonlar ve Yuvalar dersinde tanımlanan yuva kavramının yönlendirmedeki karşılığıdır: içerik dışarıdan gelir, kap onu nereye koyacağını söyler.

Bir düğümün kendi yolu göreli yazılır. :kimlik düğümü istasyon düğümünün altında durduğu için tam yolu /istasyon/:kimlik olur; tanımda bu ön ek yinelenmez. Böylece bir alt ağaç tümüyle başka bir yere taşındığında içindeki tanımlar değişmez.

Üçüncü bir düğüm türü gerekir. /istasyon yolu istendiğinde IstasyonKabugu düzeni eşleşir, ama yuvaya konacak bir alt görünüm yoktur. Bu boşluğu dizin rotası doldurur: yol tüketildiğinde eşleşen, kendi dilimi olmayan çocuk. Dizin rotası düzenin varsayılan içeriğidir.

Eşleşmeden Zincire

Ağaç üzerinde eşleşme, kökten yaprağa doğru dilim tüketerek ilerler. Sonuç tek bir bileşen değil, kökten yaprağa uzanan bir düzen zinciridir. Ekranda bu zincir içten dışa yerleşir: her bileşen bir sonrakini kendi yuvasında barındırır.

// rota-agaci.mjs — ic ice rota agacindan etkin duzen zincirinin uretilmesi
const agac = {
  yol: "", bilesen: "Kabuk", cocuklar: [
    { dizin: true, bilesen: "Karsilama" },
    { yol: "oturum", bilesen: "OturumAc" },
    {
      yol: "istasyon", bilesen: "IstasyonKabugu", cocuklar: [
        { dizin: true, bilesen: "IstasyonListesi" },
        { yol: "yeni", bilesen: "IstasyonFormu" },
        {
          yol: ":kimlik", bilesen: "IstasyonKunyesi", cocuklar: [
            { dizin: true, bilesen: "IstasyonOzeti" },
            { yol: "olcum", bilesen: "OlcumGecmisi" },
            { yol: "ayar", bilesen: "IstasyonAyarlari" },
          ],
        },
      ],
    },
    { yol: "*", bilesen: "Bulunamadi" },
  ],
};

const SIRA = (d) => d.dizin ? 0 : d.yol === "*" ? 3 : d.yol.startsWith(":") ? 2 : 1;

function coz(dugum, kalan, zincir, parametre) {
  if (dugum.dizin) return kalan.length === 0
    ? { zincir: [...zincir, dugum.bilesen], parametre } : null;

  let tuketilen = 0, p = parametre;
  if (dugum.yol === "*") { p = { ...p, kalan: kalan.join("/") }; tuketilen = kalan.length; }
  else if (dugum.yol !== "") {
    if (kalan.length === 0) return null;
    if (dugum.yol.startsWith(":")) p = { ...p, [dugum.yol.slice(1)]: decodeURIComponent(kalan[0]) };
    else if (dugum.yol !== kalan[0]) return null;
    tuketilen = 1;
  }

  const yeniZincir = [...zincir, dugum.bilesen];
  const yeniKalan = kalan.slice(tuketilen);
  for (const cocuk of [...(dugum.cocuklar ?? [])].sort((a, b) => SIRA(a) - SIRA(b))) {
    const sonuc = coz(cocuk, yeniKalan, yeniZincir, p);
    if (sonuc) return sonuc;
  }
  return (dugum.cocuklar ?? []).length === 0 && yeniKalan.length === 0
    ? { zincir: yeniZincir, parametre: p } : null;
}

const eslestir = (yol) => coz(agac, yol.split("/").filter(Boolean), [], {});

const yollar = ["/", "/oturum", "/istasyon", "/istasyon/yeni", "/istasyon/kuzey-yamac",
  "/istasyon/kuzey-yamac/olcum", "/istasyon/kuzey-yamac/ayar", "/rapor/2024"];

console.log("-- etkin duzen zinciri --");
for (const yol of yollar) {
  const { zincir, parametre } = eslestir(yol);
  console.log(yol.padEnd(30), zincir.join(" > ").padEnd(52), JSON.stringify(parametre));
}

console.log("-- gezinmede korunan ve degisen --");
const gecisler = [
  ["/istasyon", "/istasyon/kuzey-yamac"],
  ["/istasyon/kuzey-yamac", "/istasyon/kuzey-yamac/olcum"],
  ["/istasyon/kuzey-yamac/olcum", "/istasyon/kuzey-yamac/ayar"],
  ["/istasyon/kuzey-yamac/olcum", "/istasyon/dogu-sirt/olcum"],
  ["/istasyon/kuzey-yamac/olcum", "/oturum"],
];
for (const [onceki, sonraki] of gecisler) {
  const a = eslestir(onceki), b = eslestir(sonraki);
  let ortak = 0;
  while (ortak < a.zincir.length && ortak < b.zincir.length &&
    a.zincir[ortak] === b.zincir[ortak]) ortak += 1;
  const parametreAyni = JSON.stringify(a.parametre) === JSON.stringify(b.parametre);
  console.log(
    `${onceki} -> ${sonraki}`.padEnd(58),
    "korunan:", String(ortak),
    "| degisen:", (b.zincir.slice(ortak).join(" > ") || "-").padEnd(24),
    "| parametre ayni:", parametreAyni,
  );
}
-- etkin duzen zinciri --
/                              Kabuk > Karsilama                                    {}
/oturum                        Kabuk > OturumAc                                     {}
/istasyon                      Kabuk > IstasyonKabugu > IstasyonListesi             {}
/istasyon/yeni                 Kabuk > IstasyonKabugu > IstasyonFormu               {}
/istasyon/kuzey-yamac          Kabuk > IstasyonKabugu > IstasyonKunyesi > IstasyonOzeti {"kimlik":"kuzey-yamac"}
/istasyon/kuzey-yamac/olcum    Kabuk > IstasyonKabugu > IstasyonKunyesi > OlcumGecmisi {"kimlik":"kuzey-yamac"}
/istasyon/kuzey-yamac/ayar     Kabuk > IstasyonKabugu > IstasyonKunyesi > IstasyonAyarlari {"kimlik":"kuzey-yamac"}
/rapor/2024                    Kabuk > Bulunamadi                                   {"kalan":"rapor/2024"}
-- gezinmede korunan ve degisen --
/istasyon -> /istasyon/kuzey-yamac                         korunan: 2 | degisen: IstasyonKunyesi > IstasyonOzeti | parametre ayni: false
/istasyon/kuzey-yamac -> /istasyon/kuzey-yamac/olcum       korunan: 3 | degisen: OlcumGecmisi             | parametre ayni: true
/istasyon/kuzey-yamac/olcum -> /istasyon/kuzey-yamac/ayar  korunan: 3 | degisen: IstasyonAyarlari         | parametre ayni: true
/istasyon/kuzey-yamac/olcum -> /istasyon/dogu-sirt/olcum   korunan: 4 | degisen: -                        | parametre ayni: false
/istasyon/kuzey-yamac/olcum -> /oturum                     korunan: 1 | degisen: OturumAc                 | parametre ayni: false

Kök düğümün kendi yolu boştur; hiçbir dilim tüketmez ama zincirin başında durur. Bu, tüm uygulamayı saran kabuğun tanımıdır. Parametre ağacın tek bir düğümünde çıkarılır ve o düğümün altındaki her görünüme aynı değerle ulaşır: ölçüm geçmişi de, istasyon ayarları da kimlik değerini yeniden çözümlemez.

Gezinmede Ne Korunur

Çıktının ikinci bölümü iç içe rotanın asıl kazancını sayıyla gösterir. İki zincirin ortak ön eki, gezinmede yerinde kalan bileşenlerdir; ondan sonrası değişir.

Ölçüm geçmişinden istasyon ayarlarına geçişte üç bileşen korunur. Kabuk, istasyon kabuğu ve istasyon künyesi ağaçta yerinde durur; yalnızca en içteki yuva yeni içerikle dolar. Yeniden çizilmedikleri için içlerindeki durum da yaşamaya devam eder: açık yan gezinme açık kalır, künyedeki veri yeniden istenmez.

Oturum açma ekranına geçişte korunan bileşen sayısı bire düşer. Zincirin geri kalanı sökülür; sökülen bileşenlerin yerel durumu kaybolur. Bu, iç içe rota tanımının bir yan etkisi değil, doğrudan ifade ettiği karardır: hangi bölümün hangi gezinmelerde yaşayacağı ağacın biçimiyle belirlenir.

Dördüncü satır tek başına bir tuzağı gösterir. kuzey-yamac istasyonundan dogu-sirt istasyonuna geçildiğinde düzen zinciri birebir aynıdır — dört bileşenin dördü de korunur — ama parametre değişmiştir. Bileşenler yerinde kaldığı için yeniden kurulmazlar; ekranda hâlâ önceki istasyonun verisi durur. Doğru davranış, parametreye bağlı verinin parametre değişimini de dinlemesidir. Bu, Bileşen Tabanlı Arayüz Geliştirme kursundaki yan etki dersinin bağımlılık kuralının yönlendirmedeki karşılığıdır: veri isteğinin bağımlılığı bileşenin varlığı değil, parametrenin değeridir.

Bulunamadı Rotasının Yeri

Ağaçta joker düğümü hangi düzeyde durursa, bulunamadı görünümü o düzeyin kabuğu içinde görünür. Örnekteki joker kökün çocuğudur; /rapor/2024 isteğinde zincir kabuk ile bulunamadı görünümünden oluşur, yani kullanıcı üst başlığı ve gezinmeyi görmeye devam eder.

Joker istasyon düğümünün altına konsaydı /istasyon/kuzey-yamac/bilinmeyen yolu istasyon kabuğunun içinde bir hata gösterirdi; kullanıcı istasyon bağlamını kaybetmezdi. İkisi de geçerli tasarımlardır ve seçim kullanıcının nereye dönebilmesi gerektiğine bağlıdır. Yanlış olan tek şey, jokeri hiç tanımlamamaktır: o durumda tanımsız adres boş bir ekran üretir.

Sunucu tarafındaki karşılığı unutulmamalıdır. Bulunamadı görünümünü istemcinin çizmesi, sunucunun o adrese başarılı yanıt vermesi anlamına gelmez; Geçmiş ve Konum dersinde kurulan kural gereği gerçekten bulunmayan adres yine bulunamadı durum kodunu almalıdır.

Yolsuz Düzen Düğümleri

Ağaçtaki her düzen bir dilim tüketmek zorunda değildir. Kendi yolu boş olan bir düğüm, adresi değiştirmeden yalnızca bir çerçeve ekler. Bunun iki kullanımı vardır.

Birincisi görsel gruplamadır: birkaç rota aynı dar sütun düzenini paylaşıyorsa, o düzen adres hiyerarşisine yeni bir dilim eklemeden ortak bir üst düğüme çıkarılır. Kullanıcının gördüğü adres sadeleşmiş kalır.

İkincisi davranış paylaşımıdır: aynı erişim koşulunu ya da aynı veri yüklemesini paylaşan rotalar yolsuz bir düğümün altında toplanır. Erişim koşulunun bu düğümlerde nasıl işletileceği sonraki iki dersin konusudur.

Karşı yönde bir seçenek daha vardır: bir dilim tüketen ama kendi görünümü olmayan düğüm. Bu düğüm adres hiyerarşisini derinleştirir, ekrana bir şey eklemez; alt görünüm doğrudan üst yuvaya yerleşir.

Özet

  • Rota ağacı, adresin hiyerarşisini rota tanımının hiyerarşisine çevirir; her düğüm bir dilim üstlenir ve alt yolları çocuklarına devreder.
  • Düzen bileşeni alt görünümü bir yuvada barındırır; dizin rotası, yol tüketildiğinde düzenin varsayılan içeriğini sağlar.
  • Eşleşmenin çıktısı tek bileşen değil, kökten yaprağa uzanan bir düzen zinciridir; parametre ağaçta bir kez çıkarılır ve altındaki tüm görünümlere ulaşır.
  • Gezinmede iki zincirin ortak ön eki yerinde kalır ve içindeki durum korunur; ayrılan bölüm sökülüp yeniden kurulur.
  • Zincir aynı kalıp yalnız parametre değiştiğinde bileşenler yeniden kurulmaz; parametreye bağlı verinin bu değişimi kendi bağımlılığı olarak izlemesi gerekir.
  • Joker düğümünün ağaçtaki düzeyi, bulunamadı görünümünün hangi kabuğun içinde görüneceğini belirler.

Sonraki Adım

Ağaç, yolun taşıdığı durumu — hangi istasyon, hangi bölüm — bileşenlere ulaştırdı. Ekranın geri kalan durumu ise henüz adreste değil. Ölçüm geçmişi sayfasında bir tarih aralığı seçili, bir ölçüm türü süzülmüş, liste ikinci sayfada ve tarihe göre azalan sıralanmış olabilir. Bunlar bileşenin yerel değişkenlerinde tutulduğunda kullanıcı o görünümü paylaşamaz, yer imine ekleyemez ve geri düğmesiyle önceki süzgece dönemez. Sonraki ders hangi durumun yola, hangisinin sorguya yazılacağını, sorgu durumunun nasıl serileştirilip geri çözümleneceğini ve varsayılan değerlerin adresi nasıl kirletmeden bırakılacağını ele alır.

İlerlemeni kaydetmek ve not almak için Giriş yap

Notlarım

Not almak için giriş yapmalısın.

Aramak için yazmaya başlayın.

↑↓ Esc gezin · aç · kapat