---
title: 'Form Durum Yönetimi'
source: 'https://academia.sh/tr/kurslar/frontend-mimarisi/form-durum-yonetimi'
course: 'Uygulama Mimarisi: Yönlendirme, Durum ve Veri'
language: tr
updated: '2026-08-17T18:09:20+00:00'
license: 'CC BY-SA 4.0'
---

# Form Durum Yönetimi

Alan değerinin belgede mi uygulamanın durumunda mı tutulacağı, iki yaklaşımın bildirim maliyeti, form durumunun değerlerden başka taşıdığı bilgiler ve başlangıç değeri ile kirliliğin gönderim akışındaki rolü.

Veri erişimi konusu akışı tek yönde kurdu: sunucudan ekrana. Kuzey Yamaç arayüzünün ikinci
yarısı ters yönde çalışır. Gözlemci ölçüm giriş formunu açar, istasyonu seçer, değeri
yazar, notu ekler ve gönderir. Bu akışın ilk sorusu teknik olarak küçük ama sonuçları
büyüktür: **alanın o anki değeri nerede durur?**

İki cevap vardır. Değer belgenin kendisinde durabilir — alan yazılanı tutar, uygulama
gerektiğinde okur. Ya da değer uygulamanın durumunda durur — alan yalnızca durumu gösterir,
her tuş vuruşu durumu günceller ve alan güncellenmiş durumdan yeniden çizilir. Bu ders iki
cevabın ne kazandırıp ne götürdüğünü ve form durumunun değerlerden başka neler taşıdığını
ele alır.

## İki Doğruluk Kaynağı

**Denetimsiz alan (uncontrolled input)**, değerin belgede tutulmasıdır. Alan kendi
durumunu yönetir; uygulama başlangıç değerini verir, sonra araya girmez. Değer gönderim
anında ya da gerektiğinde okunur. Web'in Temelleri ve HTML kursunda tanımlanan giriş
listesi bu yaklaşımın doğal karşılığıdır: tarayıcı alanları zaten toplar.

**Denetimli alan (controlled input)**, değerin uygulamanın durumunda tutulmasıdır. Alan
gösterilen değeri durumdan alır ve her değişiklikte durumu güncelleyen bir olay bildirir.
Uygulama, kullanıcının gördüğü değeri her an bilir ve değiştirebilir.

Ayrımın kaynağı Tarayıcı ve Web Platformu kursundaki öznitelik–özellik ayrımıdır: alanın
başlangıç değeri işaretlemede bildirilen özniteliktir, o anki değeri ise ögenin
özelliğidir. Denetimsiz alan ikisinin ayrı yaşamasına izin verir; denetimli alan her
değişiklikten sonra ikisini eşitler.

Denetimlilik neyi mümkün kılar? Değerin **yazılırken dönüştürülmesini** — büyük harfe
çevirme, biçim maskesi uygulama, izin verilmeyen karakteri düşürme. Alanlar arası
**bağımlılığı** — istasyon değişince birim listesinin daralması. **Anlık doğrulamayı** ve
değere bağlı arayüz kararlarını. Bir de kaydedilmemiş taslağın saklanmasını: değer zaten
uygulamanın elindedir.

Neyi pahalılaştırır? Her tuş vuruşu bir durum güncellemesi ve bir yeniden çizim üretir.
Otuz alanlı bir formda bu maliyet ölçülebilir hâle gelir.

## Bildirim Maliyeti

Maliyetin büyüklüğü **abonelik tanesine** bağlıdır: durum değiştiğinde kim haberdar
ediliyor? Aşağıdaki model iki uç yaklaşımı sayıyor — form durumunun tamamına abone olan
alanlar ile yalnız kendi değerine abone olan alanlar.

```js
// abonelik-tanesi.mjs — form duzeyinde ve alan duzeyinde bildirim maliyeti
const ALANLAR = ["istasyon", "tarih", "deger", "birim", "not",
                 "gozlemci", "cihaz", "ruzgar", "nem", "basinc", "kar", "aciklama"];

function depo(taneler) {                 // taneler: "form" | "alan"
  const aboneler = new Map();            // yol -> islev listesi
  const cizim = new Map();               // alan -> cagrilma sayisi
  return {
    abone(yol, alan) {
      const anahtar = taneler === "form" ? "*" : yol;
      if (!aboneler.has(anahtar)) aboneler.set(anahtar, []);
      aboneler.get(anahtar).push(alan);
      cizim.set(alan, 0);
    },
    yaz(yol) {
      const anahtar = taneler === "form" ? "*" : yol;
      for (const alan of aboneler.get(anahtar) ?? []) {
        cizim.set(alan, cizim.get(alan) + 1);
      }
    },
    toplam: () => [...cizim.values()].reduce((t, s) => t + s, 0),
  };
}

// Kullanicinin tus dizisi: uc alana toplam 30 degisiklik.
const TUSLAR = [
  ...Array(14).fill("aciklama"),
  ...Array(10).fill("deger"),
  ...Array(6).fill("not"),
];

for (const taneler of ["form", "alan"]) {
  const d = depo(taneler);
  for (const a of ALANLAR) d.abone(a, a);
  for (const yol of TUSLAR) d.yaz(yol);
  console.log(
    `${taneler.padEnd(5)} tanesi:`,
    `${TUSLAR.length} değişiklik →`,
    `${String(d.toplam()).padStart(4)} alan çizimi`);
}

// Denetimsiz alan: deger belgede durur, gonderimde bir kez okunur.
const d = depo("alan");
for (const a of ALANLAR) d.abone(a, a);
console.log("denetimsiz  :", `${TUSLAR.length} değişiklik →`,
            `${String(d.toplam()).padStart(4)} alan çizimi`);
```

```
form  tanesi: 30 değişiklik →  360 alan çizimi
alan  tanesi: 30 değişiklik →   30 alan çizimi
denetimsiz  : 30 değişiklik →    0 alan çizimi
```

Sayılar oranı gösteriyor: form tanesinde her değişiklik on iki alanı çizdiriyor, alan
tanesinde yalnız değişeni. On iki katlık fark, alan sayısıyla doğru orantılı büyür.

Buradan çıkan kural, "denetimli alan pahalıdır" değil, **"denetimli alanı form tanesinde
kurmak pahalıdır"**dır. Değer uygulamanın durumunda tutulsa bile abonelik alan bazında
kurulursa maliyet tek alanla sınırlı kalır. Çoğu durumda bu, form durumunu tek bir nesne
olarak paylaşmak yerine alan başına ayrı bir okuma yolu sunmakla sağlanır.

Üçüncü satır bir sınır durumudur: değer belgede kaldığında hiçbir çizim olmaz. Bunun
bedeli, uygulamanın kullanıcının yazdığını gönderim anına kadar bilmemesidir. Karma bir
düzen de mümkündür ve yaygındır: alanların çoğu denetimsiz, yalnız birbirine bağımlı olan
ya da yazılırken dönüştürülen alanlar denetimli.

## Form Durumu Değerlerden İbaret Değildir

Değerlerin nerede durduğu kararı verildikten sonra da form, ekranın ihtiyaç duyduğu birkaç
bilgi daha taşır. Hata iletisinin ne zaman gösterileceği, gönder düğmesinin ne zaman
kapatılacağı, sayfadan ayrılırken uyarı çıkıp çıkmayacağı bu bilgilere bağlıdır.

```js
// form-durumu.mjs — olcum giris formunun durum indirgeyicisi
const BASLANGIC = {
  istasyon: "KY-01", tarih: "2026-01-14", deger: "", birim: "C", not: "",
};

const yeniDurum = () => ({
  degerler: { ...BASLANGIC },
  dokunulan: new Set(),
  gonderiliyor: false,
  gonderimSayisi: 0,
});

const kirliAlanlar = (d) =>
  Object.keys(BASLANGIC).filter((a) => d.degerler[a] !== BASLANGIC[a]);

function indirge(d, [olay, alan, deger]) {
  switch (olay) {
    case "degisti":
      return { ...d, degerler: { ...d.degerler, [alan]: deger } };
    case "dokunuldu":
      return { ...d, dokunulan: new Set([...d.dokunulan, alan]) };
    case "gonderimBasladi":
      return { ...d, gonderiliyor: true, gonderimSayisi: d.gonderimSayisi + 1,
               dokunulan: new Set(Object.keys(BASLANGIC)) };
    case "gonderimBitti":
      return { ...d, gonderiliyor: false };
    case "kabulEdildi":                       // sunucu kaydi aldi: yeni taban
      return { ...yeniDurum(), gonderimSayisi: d.gonderimSayisi };
    case "sifirla":
      return { ...yeniDurum(), gonderimSayisi: d.gonderimSayisi };
    default:
      throw new Error(`bilinmeyen olay: ${olay}`);
  }
}

const OLAYLAR = [
  ["degisti", "deger", "-"],
  ["degisti", "deger", "-4"],
  ["degisti", "deger", "-4.2"],
  ["dokunuldu", "deger"],
  ["degisti", "not", "sabah okuması"],
  ["gonderimBasladi"],
  ["gonderimBitti"],
  ["kabulEdildi"],
];

let d = yeniDurum();
const yaz = (etiket) => console.log(
  etiket.padEnd(26),
  `deger=${JSON.stringify(d.degerler.deger).padEnd(7)}`,
  `kirli=[${kirliAlanlar(d).join(",")}]`.padEnd(18),
  `dokunulan=${d.dokunulan.size}`.padEnd(13),
  `gönderiliyor=${d.gonderiliyor}`.padEnd(19),
  `gönderim=${d.gonderimSayisi}`);

yaz("başlangıç");
for (const olay of OLAYLAR) {
  d = indirge(d, olay);
  yaz(olay.filter(Boolean).join(" "));
}

// --- Ayrilmadan uyari karari ------------------------------------------------
console.log("");
for (const senaryo of [
  ["boş form", yeniDurum()],
  ["yarım doldurulmuş", indirge(yeniDurum(), ["degisti", "deger", "-4.2"])],
  ["gönderim sonrası", d],
]) {
  const [ad, durum] = senaryo;
  const kirli = kirliAlanlar(durum);
  console.log(`${ad.padEnd(20)} kirli=${kirli.length} → ayrılma uyarısı: ` +
              (kirli.length > 0 ? "gösterilir" : "gösterilmez"));
}
```

```
başlangıç                  deger=""      kirli=[]           dokunulan=0   gönderiliyor=false  gönderim=0
degisti deger -            deger="-"     kirli=[deger]      dokunulan=0   gönderiliyor=false  gönderim=0
degisti deger -4           deger="-4"    kirli=[deger]      dokunulan=0   gönderiliyor=false  gönderim=0
degisti deger -4.2         deger="-4.2"  kirli=[deger]      dokunulan=0   gönderiliyor=false  gönderim=0
dokunuldu deger            deger="-4.2"  kirli=[deger]      dokunulan=1   gönderiliyor=false  gönderim=0
degisti not sabah okuması  deger="-4.2"  kirli=[deger,not]  dokunulan=1   gönderiliyor=false  gönderim=0
gonderimBasladi            deger="-4.2"  kirli=[deger,not]  dokunulan=5   gönderiliyor=true   gönderim=1
gonderimBitti              deger="-4.2"  kirli=[deger,not]  dokunulan=5   gönderiliyor=false  gönderim=1
kabulEdildi                deger=""      kirli=[]           dokunulan=0   gönderiliyor=false  gönderim=1

boş form             kirli=0 → ayrılma uyarısı: gösterilmez
yarım doldurulmuş    kirli=1 → ayrılma uyarısı: gösterilir
gönderim sonrası     kirli=0 → ayrılma uyarısı: gösterilmez
```

Dört ayrı bilgi görünüyor ve dördü farklı soruyu yanıtlıyor.

**Değer**, alanın içeriğidir. **Dokunulma**, kullanıcının o alanı terk edip etmediğidir;
Form Olayları dersindeki hata gösterme anı kuralı bu bilgiye dayanır — ilk üç satırda
değer değişti ama dokunulan sayısı sıfır kaldı, yani kullanıcı hâlâ yazıyor ve ona hata
göstermek erken olur.

**Kirlilik**, değerin başlangıçtan farklı olmasıdır. Bu, ayrı bir bayrak olarak tutulmaz;
başlangıç değerleriyle karşılaştırılarak **hesaplanır**. Bayrak olarak tutulsaydı,
kullanıcı bir alanı değiştirip geri eski değerine döndürdüğünde form yanlışlıkla kirli
kalırdı.

**Gönderiliyor** ve **gönderim sayısı** ayrı bilgilerdir. Birincisi düğmenin kapalı
tutulmasını sağlar; ikincisi, kullanıcının bir kez gönderim denediğini kalıcı olarak
işaretler ve bundan sonra hataların dokunulma beklenmeden gösterilmesini sağlar. Altıncı
satırda gönderim başlarken bütün alanların dokunulmuş sayıldığı görülüyor — bu tek satır,
"gönder'e basınca tüm hatalar görünsün" davranışını kurar.

## Başlangıç, Kirlilik ve Sıfırlama

Başlangıç değerleri form durumunun bir parçasıdır, kodun içine gömülü bir sabit değil.
Bunun iki nedeni vardır.

Birincisi kirliliğin hesaplanabilmesi. Karşılaştırma taban değeri yoksa kirlilik
bilinemez. Çıktının son bloğu bu hesabın nereye bağlandığını gösteriyor: kirli alanı olan
bir formdan ayrılmaya çalışan kullanıcıya uyarı gösterilir, temiz formda gösterilmez.
Uyarıyı her koşulda göstermek — kullanıcı hiçbir şey yazmamışken bile — arayüzü rahatsız
edici kılar ve zamanla göz ardı edilir.

İkincisi, başlangıç değerlerinin **değişebilmesi**. Var olan bir ölçümü düzenleyen form,
başlangıç değerlerini sunucudan alır. Kayıt yüklendiğinde form durumunun yeni tabana
göre kurulması gerekir; aksi hâlde yüklenen değerler kirli görünür ve boş bir formda
"kaydedilmemiş değişiklik" uyarısı çıkar.

Üç ayrı işlem sıklıkla karıştırılır. **Sıfırlama**, değerleri başlangıca döndürür.
**Temizleme**, değerleri boşaltır — bu başlangıca dönmek değildir; düzenleme formunda
ikisi çok farklı sonuç verir. **Yeni taban belirleme**, o anki değerleri yeni başlangıç
kabul eder; sunucu kaydı kabul ettikten sonra yapılan işlem budur. Çıktıda `kabulEdildi`
olayı bunu yapıyor: form temizlendi ve kirlilik sıfırlandı, ama gönderim sayacı korundu.

## Gönderim Anı

Gönderim, form durumunun en kırılgan olduğu andır ve üç kural gerektirir.

**Çift gönderim engellenir.** Gönderiliyor bayrağı doğruyken yeni bir gönderim başlatılmaz.
Düğmeyi görsel olarak devre dışı bırakmak yeterli değildir; klavyeyle tetiklenen gönderim
ya da hızlı çift tıklama düğmenin durumundan önce gelebilir, bu yüzden engel durumda
kurulur. Bu, Yeniden Deneme ve Geri Çekilme dersindeki tekillik anahtarının form
tarafındaki karşılığıdır — engel istemcide, güvence sunucudadır.

**Sunucudan gelen alan hataları forma bağlanır.** REST İstemcisi dersinde 422 yanıtının
gövdesi `ayrinti` alanında taşınıyordu; o gövdedeki alan adları form alanlarıyla eşleşir
ve hatalar ilgili alanların yanına yerleşir. Eşleşmeyen bir alan adı gelirse hata form
düzeyinde gösterilir, yutulmaz.

**Başarısız gönderimde değerler korunur.** Kullanıcının doldurduğu formu sunucu reddetti
diye boşaltmak, işi baştan yaptırmaktır. Değerler yerinde kalır, yalnız hatalar eklenir.

Gönderimin kullanıcı algısındaki süresi ayrı bir konudur. Kaydın sunucuda kabul
edileceğini varsayıp ekranı hemen güncellemek — ve hata gelirse geri almak — Durum
Yönetimi konusundaki iyimser güncellemenin form tarafındaki uygulamasıdır. Yarım kalan
formun taslak olarak saklanması ise Kalıcı Durum dersindeki depolama kararına dayanır;
saklanan taslağın hangi başlangıç değerleriyle karşılaştırılacağı, yukarıdaki taban
kuralıyla belirlenir.

## Özet

- Alan değeri ya belgede tutulur (denetimsiz) ya uygulamanın durumunda (denetimli);
  ayrımın kaynağı öznitelik ile özelliğin ayrı yaşayıp yaşamamasıdır.
- Denetimlilik yazılırken dönüştürme, alanlar arası bağımlılık ve anlık doğrulamayı mümkün
  kılar; bedeli her değişiklikte üretilen bildirimdir.
- Bildirim maliyetini belirleyen şey denetimlilik değil abonelik tanesidir; alan bazında
  abonelik on iki alanlı bir formda çizim sayısını on ikide bire indirir.
- Form durumu değerlerin yanında dokunulma, kirlilik, gönderiliyor bayrağı ve gönderim
  sayısını taşır; her biri farklı bir arayüz kararını besler.
- Kirlilik bayrak olarak tutulmaz, başlangıç değerleriyle karşılaştırılarak hesaplanır;
  sıfırlama, temizleme ve yeni taban belirleme üç ayrı işlemdir.
- Gönderimde çift gönderim durum düzeyinde engellenir, sunucudan gelen alan hataları
  ilgili alanlara bağlanır ve başarısızlıkta kullanıcının girdiği değerler korunur.

## Sonraki Adım

Bu ders formun değerlerini tuttu ama değerlerin **kabul edilebilir olup olmadığına** hiç
bakmadı. Ölçüm değeri sayı olmalı, sıcaklık için makul bir aralıkta durmalı, tarih
gelecekte olmamalı. Bu kuralların iki yerde bilinmesi gerekir: kullanıcıya anında geri
bildirim vermek için istemcide, isteğin sayfa hiç kullanılmadan da kurulabildiğini bilerek
sunucuda. Aynı kuralı iki yere ayrı ayrı yazmak, ikisinin zamanla ayrışması demektir.
Sonraki ders kuralları tek bir bildirimde toplar ve aynı bildirimin iki tarafta aynı sonucu
verdiğini gösterir.
