Herkese merhabalar. Bugün angular ekosisteminde NGXS kullanarak nasıl state management yapacağımızı inceleyeceğiz. Angular state management kimi zaman korkutucu gelebilir. Angular zaten karışık işin içine state management girdiğinde işler daha da çok karışıyor diye düşünebilirsiniz. O yüzden bu yazıda olabildiğince küçük küçük adımlar atarak sadece 5 dakika içerisinde nasıl state yönetimi kurabileceğinizi detaylı bir şekilde açıklayacağım.
State Management Nedir ?
Başlamadan önce state management nedir bu konuya değinmek istiyorum. Amacım bazı şeyleri neden yaptığımızı daha iyi anlamak. Bazen ya ne gerek vardı diye düşünüyor olabilirsiniz. Gerçekten de state management kütüphanesi kullanmak zorunda değilsiniz. Projeden projeye değişebilir elbette ancak kimi projelerde çalışırken state management bazen çok gereksiz bir feature olabilir.
Örneğin sürekli canlı data ile çalıştığınız ve datanın çok fazla değişkenlik gösterdiği projelerde state management kütüphanesi kullanmak sizin için bir avantaj olmayabilir. Sürekli state içerisinde tutulan verileri çeşitli kondisyonlar üzerinden tekrar tekrar yenilemek hem zamanınızı alacaktır hem de potansiyel bir çok bug’ın oluşmasına sebebiyet verecektir. Yahut birbiri ile çok az ilişkisi olan domainlerin olduğu ve çoğunlukla crud işlemlerinin yapıldığı bir panel geliştirirken de state management size büyük bir avantaj sağlamayacaktır. Temiz bir altyapı oluşturmak için tercih edebilirsiniz ancak size pratik bir yararı fazla yok diyebilirim
Peki ne zaman kullanmalıyız ? Kısaca şöyle özetleyebiliriz. Diyelim ki bir uygulama geliştiriyorsunuz ve uygulamanızın çok çeşitli componentleri var. Bu componentler aktif bir şekilde birbirleri ile iletişim halindeler. Componentlerimiz, uygulamamızı bir ağaç gibi düşünürsek uygulamanın her hangi bir yerinde olabilirler. Dolayısıyla componentler arasında iletişimi sağlarken gereksiz karmaşıklıktan kaçınmak için state management kütüphanelerini tercih edebilirsiniz. Elbette bu sadece bir örnek. Benzer bir çok durumda; authentication – oturum yönetimi, kart yönetim işlemler, ilişkisel veri yönetim işlemleri vb gibi durumlarda state management uygulamaları sayesinde codebase’i gereksiz karmaşadan uzak tutarak rahat bir şekilde geliştirme yapabilirsiniz.
NGXS vs NGRX ?
Angular ekosisteminde popüler olan iki kütüphane yer alıyor bunlar; NGRX ve NGXS. Ben genellikle NGXS ile çalışmayı daha çok seviyorum. Nedeni ise NGRX tam anlamıyla standart bir state management kütüphanesi iken NGXS gelişmiş özellikleri ile Angular’a daha entegre çalışmaktadır ve bizi bir çok boilerplate’den kurtarmaktadır. Bir state açmak ve açılan state’i yönetmek NGXS’de çok daha basit, hızlı ve etkilidir.
NGRX diğer state management kütüphaneleri gibi actions – reducer – selector. hayat döngüsü üzerine kurulmuştur ve bu döngüyü sağlamak için çok fazla boilerplate kod yazmanız gerekmektedir.
NGXS ise merkezinde state adını verdiğimiz reducer benzeri bir yapıdan oluşmaktadır ve bütün işlemler state çerçevesinde çok daha az boilerplate ile gerçekleşmektedir. Bu yüzden hem daha hızlı ve temiz bir şekilde state management gerçekleşterebilirsiniz.
NGXS State Management – Kurulum
Öncelikle aşağıda listelediğim npm paketlerini indirmekle başlıyoruz. Hem store paketini hem de devtools paketini indireceğiz. Devtools zorunlu değil ancak yapılan işlemleri tarayıcı üzerinde debug etmek için kesinlikle kullanmanızı tavsiye ediyorum.
npm install @ngxs/store @ngxs/devtools-plugin
Paketleri indirdikten sonra app/store içerisinde StoreModule adını verdiğimiz modülü oluşturuyoruz ve sonrasında AppModule içerinde import ediyoruz.
NGXS’i projeye entegre edebilmek için store modülü oluşturmak zorunda değilsiniz ancak SOLID prensiblerine uygun yazalım. Single Responsibility’e özen gösterelim diyorsanız tanımlamalarınızı StoreModule oluşturarak burada gerçekleştirebilirsiniz.
Store module içerisinde şu an için 2 module import ettik. Ancak bu 2 modülün dışında NGXS veya NGXS Lab tarafından sunulan çeşitli ekstra modüller de eklenebilir.
- NgxsModule – NGXS kullanabilmek için uygulama içerisinde bu modülü root olarak bir kere tanımlamamız gerekiyor.
- NgxsReduxDevtoolsPluginModule – Bu modülü ise redux dev tools eklentisi üzerinden uygulamamızı debug edebilmek için kuruyoruz. State içerisinde gerçekleşen bütün işlemleri bu eklenti üzerinden rahatça takip edebiliyoruz. Sadece debug değil aynı sırada geliştirme sırasında da bize büyük kolaylıklar sunuyor. Eklenti üzerinden state içerisinde olan verilerin cachelenmesini sağlayabilirsiniz. Bu sayede yaptığınız bir değişiklik ile uygulama yenilendiğinde state’in son halini koruyabilirsiniz.
- Name – Oluşturduğunuz store için bir isim verebilirsiniz. Eklenti bütün tablarda açık olan store’lara bağlanabilir. Store’ları birbirinden ayırmak için izin vermeniz iyi olabilir.
- Max Age – Eklenti üzerinde dispatch edilen bütün actionları görebiliyoruz. Ancak bütün actionları loglamak debug performansını düşürebilir. O yüzden eklentiye sadece son 50 action’u hatırla diyebiliriz.
- Disabled – Uygulamayı production ortamına aldığınızda store içeriisnde olan bilgilerin expose olmasını istemeyebilirsiniz. Anguların bize sağlamış olduğu isDevMode() metodunu kullanarak, production build aldığımızda devtools eklentisini devredışı bırakabiliriz.
State Yapısının Oluşturulması
Şimdi ise ilk state sınıfımızı oluşturalım ve NGXS içerisinde state management nasıl çalışıyor gelin hep birlikte görelim. Aşağıda minik bir e ticaret uygulaması geliştireceğiz. Dolayısıyla domainimiz eticaret üzerine olacak. Yazının sonrasında oluşturduğumuz minik projenin github linkini de bulabilirsiniz. Ancak indirmeden önce adım adım kendi projenizi oluşturmanız anlamanız ve hatırlamanız açısından sizin için çok daha iyi olabilir. Lafı daha fazla uzatmadan adım adım anlatmaya başlıyorum 🙂
Eticaret uygulamamız için 2 adet state oluşturuyoruz. Birincisi products, ikincisi ise cart.
Statelerimizi Adım Adım Oluşturuyoruz
NGXS tarafından sağlanan State selectörünü kullanarak statelerimizi oluşturuyoruz. Bu statelerimiz içerisinde selectorlerimiz ve aşağıda tanımlayacağız actionlar için dispatcherlarımız olacak.
1 – İlk önce servisimi oluşturuyoruz. Bu uygulama için fake data oluşturmak yerine dummy json üzerinden fake veriler çekeceğiz. Dummy json platformu üzerinde çeşitli sektörlere ait dummy veriler rest olarak sunuluyor. Biz ecommerce projesi üzerinde çalıştığımız için products bilgilerini çekiyoruz.
Rest apiye bağlanırken url adresini bütün olarak yazmak yerine sadece products kısmını yazmış olmam bazılarınızın dikkatini çekmiş olabilir. Dummy jsona istek atabilmek için gönderilen isteklere api adresini eklediğim bir interceptor oluşturdum. Aşağıda yer alan github linki üzerinden projeyi inceleyebileceğiniz gibi blog üzerine paylaştığım Angular Interceptor Nedir ve Nasıl Kullanılır başlıklı yazıma da göz atabilirsiniz.
2 – Şimdi ise State için bir model oluşturuyoruz. Bu modelin içerisinde state içerisinde olması gereken propertylerin tanımlamalarını yapıyoruz. Rest servis üzerinden bize paginated bir yanıt döneceği için pagination ile ilgili bilgileri de state içerisinde tanımlıyoruz.
3 – Modeli tanımladıktan sonra state’imizi bu model doğrultusunda oluşturuyoruz. Bu state içerisinde action dispatcherlarımız ve selectorlerimiz yer alıyor.
State’imiz içerisinde şu an için sadece bir action üzerinden işlemlerimizi gerçekleştiriyoruz. Örneğin GetProducts actionu dispatch olduğunda products servisimizi çağırıyoruz ve çektiğimiz ürünleri state içerisinde tutuyoruz. Şimdi şöyle bir sorunuz olaiblir. Servisi tanımladık, state tanımladık, ee action nereden geldi ? Onu nasıl tanımlıyoruz diye soran olursa onu da hemen açıklayalım.
Her selector ve action için bir metod açıyoruz arkadaşlar ancak burada şöyle bir nüans var. Selector için yazdığımız metodların static olarak tanımlanması gerekiyor.
Diğer önemli husus ise selector olarak tanımladığımız metodları @Selector, actionlar için tanımladığımız metodları ise @Action dekoratörü ile işaretlememiz gerekiyor. Bu sayede actionlar ve metodlar arasında linkleme yapabiliyoruz. Uygulama ayağa kaldırıldığında NGXS hangi dispatch için hangi metodu çağırması gerektiğini bu sayede biliyor. Klasik redux mimarisinda olduğu gibi sonsuz switch caseler ile veya chained metodlar ile boğuşmak zorunda kalmıyorsunuz. Daha OOP standartlarına uygun, daha okunabilir bir şekilde state management işlemlerimizi gerçekleştirebiliyoruz.
4 – State içerisinde kullanacağımız actionları ayrı dosya içerisinde tanımlıyoruz.
Event driven design’a benzer bir şekilde nasıl event oluşturuyorsak, NGXS ile çalışırken store/state ile olan haberleşmemizi action kullanarak gerçekleştiriyoruz.
State Nasıl Kullanılır ?
İlk state’imizi oluşturduk arkadaşlar şimdi ise oluşturduğumuz bu state’i kullanmaya geldi. Uygulama içerisinde bu state’e erişmek istediğiniz componentlerde bir takım küçük tanımlamalar yapmanız gerekiyor.
1 – Product componentini yer aldığı module içerisine state’imizi ekliyoruz. Eğer lazy loaded modules kullanmıyorsanız, stateinizi doğrudan root düzeyde NgxsModule.forRoot([…]) içerisinde tanımlamanız gerekiyor. Lazy load modüller ile çalışırken ise NgxsModule.forFeature([…]) metodunu kullanıyoruz.
2 – Şimdi ise component içerisine girelim. Component içerisinde store’a ve state’e nasıl erişeceğimizi actionları nasıl kullanacağımızı verileri nasıl yükleyeceğimize bakalım.
Burada karşımıza yeni bir selector çıkıyor. Component içerisinde tanımladığımız propertyleri, örneği products, @Select dekoratörü ile işaretleyerek herhangi bir atama (assign) işlemi olmadan state içerisinde yer alan verilerimizi bu değişkene atayabiliyoruz. Componentimiz içerisinde tanımladığımız bu değişkenimiz observable bir şekilde verdiğimiz selectore ait verileri çekebiliyor. Angular tarafından component init edildiğinde bu atama işlemi arka planda gerçekleşiyor. Manual olarak bir işlem yapmanız gerekmiyor.
Önceki adımlarda oluşturduğumuz GetProducts adlı action’umuzu da ngOnInit hook içerisinde dispatch ediyoruz. Bu sayede sayfa açıldığında ve component initate edildiğinde servisten verilerimizi çekebiliyoruz. Template içerisinde ise bu verilerimizi for içerisine iterate ettiğimiz ise wolaaa!
Gördüğünüz üzere sadece 5 dakikada state’imiz hazır arkadaşlar. Ben NGXS’i sık kullandığım için 5 dk da oluşturabiliyorum ama sizin bir kaç dk daha fazla zamanınızı alabilir 🙂
Arkadaşlar konu çok uzamaya başladı o yüzden 2 part a bölüyorum. Part 2 içerisinde ise basket state oluşturup tek state üzerinden birden fazla sayfa ve component üzerinde işlemler gerçekleştireceğiz. Şu ana kadar anlattığımız konularda takıldığınız noktalar olursa sormaktan çekinmeyin. Hatta genel olarak eğitim ve iş hayatınızda takıldığınız noktalar olduğu zaman, tecrübeniz farketmeksizin, her zaman çevrenizdekinleri insanlara soru sormalısınız. Daha fazla uzatmadan part 2 de görüşmek üzere 🙂
Hocam çok güzel anlatmışsınız <3