You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
Web-Dev-For-Beginners/translations/tr/7-bank-project/4-state-management/README.md

17 KiB

Bir Bankacılık Uygulaması Geliştirme Bölüm 4: Durum Yönetimi Kavramları

Ders Öncesi Test

Ders öncesi test

Giriş

Bir web uygulaması büyüdükçe, tüm veri akışlarını takip etmek zorlaşır. Veriyi hangi kod alıyor, hangi sayfa tüketiyor, nerede ve ne zaman güncellenmesi gerekiyor... Kodun karmaşık hale gelmesi ve bakımının zorlaşması kolaydır. Bu durum, özellikle uygulamanızın farklı sayfaları arasında veri paylaşmanız gerektiğinde, örneğin kullanıcı verileriyle, daha da belirgin hale gelir. Durum yönetimi kavramı her tür programda her zaman var olmuştur, ancak web uygulamaları karmaşıklıkta büyüdükçe, geliştirme sırasında düşünülmesi gereken önemli bir nokta haline gelmiştir.

Bu son bölümde, oluşturduğumuz uygulamayı gözden geçirerek durumun nasıl yönetildiğini yeniden düşüneceğiz. Bu, tarayıcı yenilemesini herhangi bir noktada desteklemeyi ve kullanıcı oturumları arasında verilerin kalıcılığını sağlamayı içerecek.

Ön Koşul

Bu ders için web uygulamasının veri çekme bölümünü tamamlamış olmanız gerekiyor. Ayrıca Node.js kurmanız ve sunucu API'sini yerel olarak çalıştırmanız gerekiyor, böylece hesap verilerini yönetebilirsiniz.

Sunucunun düzgün çalıştığını test etmek için bir terminalde şu komutu çalıştırabilirsiniz:

curl http://localhost:5000/api
# -> should return "Bank API v1.0.0" as a result

Durum yönetimini yeniden düşünmek

Önceki derste, uygulamamızda şu anda oturum açmış kullanıcının banka verilerini içeren global account değişkeni ile temel bir durum kavramını tanıttık. Ancak, mevcut uygulamamızda bazı eksiklikler var. Gösterge panelindeyken sayfayı yenilemeyi deneyin. Ne oluyor?

Mevcut kodda 3 sorun var:

  • Durum kalıcı değil, çünkü tarayıcı yenilemesi sizi giriş sayfasına geri götürüyor.
  • Durumu değiştiren birden fazla işlev var. Uygulama büyüdükçe, bu değişiklikleri takip etmek zorlaşabilir ve birini güncellemeyi unutmak kolaydır.
  • Durum temizlenmiyor, bu yüzden Çıkış Yap'a tıkladığınızda bile giriş sayfasında olsanız da hesap verileri hala orada duruyor.

Bu sorunları tek tek ele almak için kodumuzu güncelleyebiliriz, ancak bu daha fazla kod tekrarı yaratır ve uygulamayı daha karmaşık ve bakımını zor hale getirir. Ya da birkaç dakika durup stratejimizi yeniden düşünebiliriz.

Burada gerçekten hangi sorunları çözmeye çalışıyoruz?

Durum yönetimi, şu iki temel sorunu çözmek için iyi bir yaklaşım bulmakla ilgilidir:

  • Bir uygulamadaki veri akışlarını nasıl anlaşılır hale getirebiliriz?
  • Durum verilerini her zaman kullanıcı arayüzüyle (ve tersi) nasıl senkronize tutabiliriz?

Bu sorunları çözdüğünüzde, karşılaşabileceğiniz diğer sorunlar ya zaten çözülmüş olur ya da çözülmesi daha kolay hale gelir. Bu sorunları çözmek için birçok olası yaklaşım vardır, ancak biz verileri ve bunları değiştirme yollarını merkezileştiren yaygın bir çözümle ilerleyeceğiz. Veri akışları şu şekilde olacaktır:

HTML, kullanıcı eylemleri ve durum arasındaki veri akışlarını gösteren şema

Burada, verilerin otomatik olarak görünümü tetiklediği kısmı ele almayacağız, çünkü bu daha ileri düzey Reaktif Programlama kavramlarına bağlıdır. Derinlemesine bir dalış yapmak isterseniz bu iyi bir takip konusudur.

Durum yönetimi için farklı yaklaşımlara sahip birçok kütüphane vardır, Redux popüler bir seçenektir. Büyük web uygulamalarında karşılaşabileceğiniz potansiyel sorunları ve bunların nasıl çözülebileceğini öğrenmek için kullanılan kavramlara ve desenlere göz atabilirsiniz.

Görev

Biraz yeniden düzenleme ile başlayacağız. account tanımını şu şekilde değiştirin:

let account = null;

Şununla değiştirin:

let state = {
  account: null
};

Fikir, tüm uygulama verilerimizi tek bir durum nesnesinde merkezileştirmektir. Şu anda durum içinde yalnızca account var, bu yüzden çok fazla değişiklik olmuyor, ancak bu, gelecekteki geliştirmeler için bir yol açıyor.

Ayrıca bunu kullanan işlevleri de güncellememiz gerekiyor. register() ve login() işlevlerinde, account = ... ifadesini state.account = ... ile değiştirin.

updateDashboard() işlevinin başına şu satırı ekleyin:

const account = state.account;

Bu yeniden düzenleme tek başına çok fazla iyileştirme getirmedi, ancak fikir, sonraki değişiklikler için bir temel oluşturmaktı.

Veri değişikliklerini izleme

Artık verilerimizi saklamak için state nesnesini oluşturduğumuza göre, bir sonraki adım güncellemeleri merkezileştirmektir. Amaç, herhangi bir değişikliği ve ne zaman gerçekleştiğini takip etmeyi kolaylaştırmaktır.

state nesnesinde değişiklik yapılmasını önlemek için, onu değişmez olarak düşünmek de iyi bir uygulamadır, yani hiç değiştirilemez. Bu aynı zamanda, içinde bir şey değiştirmek istiyorsanız yeni bir durum nesnesi oluşturmanız gerektiği anlamına gelir. Bunu yaparak, potansiyel olarak istenmeyen yan etkilerden korunma sağlarsınız ve uygulamanızda geri al/yeniden yap gibi yeni özellikler uygulama olasılıklarını açarsınız. Ayrıca hata ayıklamayı kolaylaştırır. Örneğin, duruma yapılan her değişikliği kaydedebilir ve bir hatanın kaynağını anlamak için değişikliklerin geçmişini tutabilirsiniz.

JavaScript'te Object.freeze() kullanarak bir nesnenin değişmez bir sürümünü oluşturabilirsiniz. Değişmez bir nesnede değişiklik yapmaya çalışırsanız, bir istisna oluşur.

Yüzeysel ve derin değişmez nesne arasındaki farkı biliyor musunuz? Buradan okuyabilirsiniz.

Görev

Yeni bir updateState() işlevi oluşturalım:

function updateState(property, newData) {
  state = Object.freeze({
    ...state,
    [property]: newData
  });
}

Bu işlevde, yeni bir durum nesnesi oluşturuyor ve önceki durumdan verileri yayılma (...) operatörü kullanarak kopyalıyoruz. Daha sonra, durum nesnesinin belirli bir özelliğini köşeli parantez notasyonu [property] kullanarak yeni verilerle değiştiriyoruz. Son olarak, Object.freeze() kullanarak nesneyi değişikliklere karşı kilitliyoruz. Şu anda durum içinde yalnızca account özelliği saklanıyor, ancak bu yaklaşımla duruma ihtiyaç duyduğunuz kadar çok özellik ekleyebilirsiniz.

state başlatmasını da güncelleyerek başlangıç durumunun da dondurulduğundan emin olun:

let state = Object.freeze({
  account: null
});

Bundan sonra, register işlevini güncelleyerek state.account = result; atamasını şu şekilde değiştirin:

updateState('account', result);

Aynısını login işlevi için yapın, state.account = data; ifadesini şu şekilde değiştirin:

updateState('account', data);

Şimdi kullanıcı Çıkış Yap düğmesine tıkladığında hesap verilerinin temizlenmemesi sorununu düzeltme fırsatını değerlendirelim.

Yeni bir logout() işlevi oluşturun:

function logout() {
  updateState('account', null);
  navigate('/login');
}

updateDashboard() içinde, return navigate('/login'); yönlendirmesini return logout(); ile değiştirin.

Yeni bir hesap kaydedip, çıkış yapıp tekrar giriş yaparak her şeyin hala düzgün çalıştığını kontrol edin.

İpucu: Tüm durum değişikliklerini görmek için updateState() işlevinin altına console.log(state) ekleyebilir ve tarayıcınızın geliştirme araçlarındaki konsolu açabilirsiniz.

Durumu kalıcı hale getirme

Çoğu web uygulamasının düzgün çalışabilmesi için verileri kalıcı hale getirmesi gerekir. Tüm kritik veriler genellikle bir veritabanında saklanır ve bir sunucu API'si aracılığıyla erişilir, bizim durumumuzda olduğu gibi kullanıcı hesap verileri. Ancak bazen, daha iyi bir kullanıcı deneyimi sağlamak veya yükleme performansını artırmak için tarayıcınızda çalışan istemci uygulamasında bazı verileri kalıcı hale getirmek de ilginç olabilir.

Tarayıcınızda veri kalıcı hale getirmek istediğinizde, kendinize sormanız gereken birkaç önemli soru vardır:

  • Veriler hassas mı? Kullanıcı şifreleri gibi hassas verileri istemcide saklamaktan kaçınmalısınız.
  • Bu verileri ne kadar süreyle saklamanız gerekiyor? Bu verilere yalnızca mevcut oturum için mi erişmeyi planlıyorsunuz yoksa sonsuza kadar mı saklamak istiyorsunuz?

Bir web uygulamasında bilgi saklamanın, neyi başarmak istediğinize bağlı olarak birden fazla yolu vardır. Örneğin, bir arama sorgusunu saklamak ve kullanıcılar arasında paylaşılabilir hale getirmek için URL'leri kullanabilirsiniz. Ayrıca, verilerin sunucuyla paylaşılması gerekiyorsa, örneğin kimlik doğrulama bilgileri gibi, HTTP çerezlerini kullanabilirsiniz.

Bir diğer seçenek, veri saklamak için tarayıcı API'lerinden birini kullanmaktır. İki tanesi özellikle ilginçtir:

  • localStorage: belirli bir web sitesine özgü verileri farklı oturumlar arasında kalıcı hale getiren bir Anahtar/Değer deposu. Burada saklanan veriler asla sona ermez.
  • sessionStorage: bu, localStorage ile aynı şekilde çalışır, ancak içinde saklanan veriler oturum sona erdiğinde (tarayıcı kapatıldığında) temizlenir.

Unutmayın ki bu iki API yalnızca dizeleri saklamanıza izin verir. Karmaşık nesneleri saklamak istiyorsanız, bunları JSON.stringify() kullanarak JSON formatına dönüştürmeniz gerekir.

Bir sunucuyla çalışmayan bir web uygulaması oluşturmak istiyorsanız, istemcide bir veritabanı oluşturmak için IndexedDB API'sini kullanmak da mümkündür. Bu, gelişmiş kullanım durumları veya önemli miktarda veri saklamanız gerektiğinde ayrılmıştır, çünkü kullanımı daha karmaşıktır.

Görev

Kullanıcılarımızın Çıkış Yap düğmesine açıkça tıklayana kadar oturumlarının açık kalmasını istiyoruz, bu yüzden hesap verilerini saklamak için localStorage kullanacağız. İlk olarak, verilerimizi saklamak için kullanacağımız bir anahtar tanımlayalım.

const storageKey = 'savedAccount';

Daha sonra updateState() işlevinin sonuna şu satırı ekleyin:

localStorage.setItem(storageKey, JSON.stringify(state.account));

Bununla birlikte, kullanıcı hesap verileri kalıcı hale gelecek ve daha önce tüm durum güncellemelerini merkezileştirdiğimiz için her zaman güncel olacak. İşte bu noktada, önceki yeniden düzenlemelerimizin faydasını görmeye başlıyoruz 🙂.

Veriler kaydedildiği için, uygulama yüklendiğinde bunları geri yüklemekle de ilgilenmemiz gerekiyor. Daha fazla başlatma koduna sahip olmaya başlayacağımız için, app.js'in altındaki önceki kodumuzu da içeren yeni bir init işlevi oluşturmak iyi bir fikir olabilir:

function init() {
  const savedAccount = localStorage.getItem(storageKey);
  if (savedAccount) {
    updateState('account', JSON.parse(savedAccount));
  }

  // Our previous initialization code
  window.onpopstate = () => updateRoute();
  updateRoute();
}

init();

Burada kaydedilen verileri alıyoruz ve eğer varsa durumu buna göre güncelliyoruz. Bunu rota güncellemesinden önce yapmak önemlidir, çünkü sayfa güncellemesi sırasında duruma bağlı kod olabilir.

Artık Gösterge Paneli sayfasını uygulamamızın varsayılan sayfası yapabiliriz, çünkü artık hesap verilerini kalıcı hale getiriyoruz. Eğer veri bulunamazsa, gösterge paneli zaten Giriş sayfasına yönlendirme yapıyor. updateRoute() içinde, yedek return navigate('/login'); ifadesini return navigate('/dashboard'); ile değiştirin.

Şimdi uygulamada oturum açın ve sayfayı yenilemeyi deneyin. Gösterge panelinde kalmalısınız. Bu güncellemeyle tüm başlangıç sorunlarımızı ele aldık...

Verileri yenileme

...Ama aynı zamanda yeni bir sorun yaratmış olabiliriz. Oops!

test hesabını kullanarak gösterge paneline gidin, ardından yeni bir işlem oluşturmak için bir terminalde şu komutu çalıştırın:

curl --request POST \
     --header "Content-Type: application/json" \
     --data "{ \"date\": \"2020-07-24\", \"object\": \"Bought book\", \"amount\": -20 }" \
     http://localhost:5000/api/accounts/test/transactions

Şimdi tarayıcıda gösterge paneli sayfasını yenilemeyi deneyin. Ne oluyor? Yeni işlemi görüyor musunuz?

Durum, localStorage sayesinde süresiz olarak kalıcı hale geldi, ancak bu aynı zamanda, uygulamadan çıkış yapıp tekrar giriş yapana kadar asla güncellenmediği anlamına geliyor!

Bunu düzeltmek için olası bir strateji, gösterge paneli her yüklendiğinde hesap verilerini yeniden yüklemek olabilir, böylece eski verilerden kaçınılır.

Görev

Yeni bir updateAccountData işlevi oluşturun:

async function updateAccountData() {
  const account = state.account;
  if (!account) {
    return logout();
  }

  const data = await getAccount(account.user);
  if (data.error) {
    return logout();
  }

  updateState('account', data);
}

Bu yöntem, şu anda oturum açmış olduğumuzu kontrol eder ve ardından hesap verilerini sunucudan yeniden yükler.

refresh adında başka bir işlev oluşturun:

async function refresh() {
  await updateAccountData();
  updateDashboard();
}

Bu işlev hesap verilerini günceller ve ardından gösterge paneli sayfasının HTML'sini günceller. Bu, gösterge paneli rotası yüklendiğinde çağırmamız gereken şeydir. Rota tanımını şu şekilde güncelleyin:

const routes = {
  '/login': { templateId: 'login' },
  '/dashboard': { templateId: 'dashboard', init: refresh }
};

Şimdi gösterge panelini yenilemeyi deneyin, güncellenmiş hesap verilerini göstermesi gerekir.


🚀 Zorluk

Artık gösterge paneli her yüklendiğinde hesap verilerini yeniden yüklüyoruz, sizce tüm hesap verilerini kalıcı hale getirmemiz hala gerekli mi?

Uygulamanın çalışması için kesinlikle gerekli olan verileri localStorage'da saklamak ve yüklemek için neyi değiştirebileceğinizi birlikte çalışarak deneyin.

Ders Sonrası Test

Post-lecture quiz

Ödev

"İşlem ekle" diyalog kutusunu uygula

İşte ödevi tamamladıktan sonra elde edeceğiniz örnek bir sonuç:

Örnek "İşlem ekle" diyalog kutusunu gösteren ekran görüntüsü

Feragatname:
Bu belge, AI çeviri hizmeti Co-op Translator kullanılarak çevrilmiştir. Doğruluk için çaba göstersek de, otomatik çevirilerin hata veya yanlışlıklar içerebileceğini lütfen unutmayın. Belgenin orijinal dilindeki hali, yetkili kaynak olarak kabul edilmelidir. Kritik bilgiler için profesyonel insan çevirisi önerilir. Bu çevirinin kullanımından kaynaklanan yanlış anlamalar veya yanlış yorumlamalar için sorumluluk kabul etmiyoruz.