STATE MANAGEMENT VE PROVIDER

Levent
Flutter Students Club

--

Flutter serüvenime başladığımdan beri internette sürekli olarak state management ifadesini görmekteydim. Bunun önemli bir şey olduğu aşikardı fakat tam olarak ne işe yaradığını bilmiyordum. Geçtiğimiz ay bu duruma son verdim ve state management konusunda bilgi edinmeye çalıştım. Sizler de state managementın ne olduğunu merak ediyorsanız gelin dilim döndüğünce sizlere bildiklerimi aktarayım. Konu sonunda da örnek bir uygulamayla pekiştirmeye çalışalım.

Flutter Docs

STATE NEDİR ?

State kavramının ne olduğu ilk başta kafamızı karıştırabilir. Bunun için önce state ifadesini açıklamaya çalışalım. Flutter utgulamalarında state uygulamanın kullanılan andaki durumudur diyebiliriz. Ephemeral State ve App State olarak ikiye ayrılmaktadır.

  1. Ephemeral State: Ephemeral State uygulamamızda anlık olarak kullandığımız ekrandaki geçici durumlardır. Örnek olarak ilk açıldığında karşımızıa çıkan sayaç uygulamasında sayacın biri göstermesi geçici bir durumdur. Uygulamamızın başka hiçbir yerinde sayacın değeri önemli değildir. Hatırlarsanız setState adlı bir metodumuz vardı. İşte bu ephemeral statelerde değişiklik yapmak için bu metodu kullanırız.Bu işlem sonucunda gerçekleşen değişimler ugulamanın başka bölümlerini ilgilendirmez.
  2. App State: App State ise kullanım sırasında sadece anlık olarak gerekmeyen, uygulamanın başka sayfalarında veya başka zamanlarında kullanılacak olan durumlardır. Bundan dolayı bir diğer adı da Shared Statetir. Diyelim ki bir ToDo uygulaması yapacaksınız . Yeni bir görev eklediğinizde bu değerin başka bir yerde depolanması gerekir ki uygulama yeniden başlatıldığında kullanıcı tekrar o değere ulaşabilsin. Ya da hava durumu uygulamasında bilgileri konuma göre hava durumunu çektiğimiz ekrandan kullanıcıya göstereceğimiz ekrana taşıyacağız. Bu durumda da devereye app state girmektedir.

Peki biz bu statelerden hangisini ne zaman kullanacağız ? Bunun sorunun kesin bir cevabı yok. Geliştirdiğiniz uygulama neyi gerektiriyorsa onu kullanmamız gerekir, karmaşık hale geldikçe app state i kullanmak mantıklı olacaktır. Kısacası;

Flutter Docs

Gelelim başlığımızın ikinci kısmına;Provider ile durum yönetimi yapmak benim gibi Flutter’da yeni olan ya da uygulaması çok fazla karmaşık olmayan geliştiriciler için oldukça basit ve anlaşılır bir yöntem. Normal şartlarda bir widget üzerindeki veriyi kendisinin altında bulunan widgetlara iletirken bunu property olarak verebiliriz. Küçük bir uygulamada bu işimizi görebilir fakat birbirine bağlı yüzlerce widget oluşturulduğunda her seferinde bu yöntemi yapmak sizce de zorlayıcı olmaz mı ? Diyelim ki bunu yaptık. Peki widget ağacının en altındaki widettan en üstteki widgeta veri taşımak istersek ne yapacağız? Gelin bu sorunun cevabını bulalım.

Bu yöntemi anlatırken basit bir ToDo uygulması üzerinden gitmek faydalı olacaktır diye düşünüyorum.

Uygulama Akış Şeması

Uygulamamızın basit şeması yukarıda gördüğünüz şekilde. Siyah oklar widgetlar arası ilişkiyi kırmızı oklar ise state bilgisinin aktarımını temsil etmektedir. Gelin yavaş yavaş uygulamamızı yazmaya başlayalım.

Uygulamamızda Provider paketini kullanabilmek için öncelikle burdan son sürümü pubspec.yaml dosyamıza eklemeliyiz. Daha sonra da projemize import etmeliyiz. Provide paketini kullanmak yanında üç farklı ifadeyi de yanında getirmektedir. Bunlar: ChangeNoifier, ChangeNotifierProvider ve Consumerdır.

ChangeNotifier uygulamamız içinde yapılan değişikliklerden gerekli yerleri haberdar etmemizi sağlar. Yapmakta olduğumuz uygulama içinde bunu nerde kullandığımızı inceleyelim;

Yukarda incelediğiniz ToDoItemData classında uygulamamız içinde saklayacağımız verileri ve bu verilerle ilgili yapılacak işlemleri (ekleme,silme,güncelleme) saklamaktayız. Bir şeyi fark etmenizi istiyorum. Bu classta veri üzerinde oynama yapan fonskiyonların gerçekleştirdiği son işlem notifyListeners() komutu. Bu komut uygulamada ToDoItemData classındaki değişikliklerden haberdar olmak zorunda olan diğer classlara en basit ifadeyle ‘ben bir değişiklik yaptım’ demektedir. Böylelikle değişen veri her yerde değişmektedir.

ChangeNotifierProvider widget ağacında bağlandığı widgetın çocuklarına gerekli bilgileri aktarmamızda işe yarar. ChangeNotifierProviderı widget ağacında olabildiğince altta kullanmak uygulamamızın performansı için daha iyi olacaktır. Biz uygulamamızda MyApp classına bağladık. Nasıl yapıldığının örneği ise aşağıda;

Konunun başlangıcında verdiğim uygulama akışından hatırlayacaksınız ki state akışını MyApp üzerinde yapıyorduk. Bundan dolayı 1. ve 6. satırlar arasında göreceksiniz ki MyApp i aynı bir widgetla sarmalar gibi ChangeNotifierProvider ile sarmaladık.

create:(context)=>ToDoItem(), child: const MyApp() ifadesinde ToDoItem() veriyi işlediğimiz, MyApp ise ChangeNotifierProvider ile sarmaladığımız widgetı ifade etmektedir. Biz uygulamamızda sadece bir tane class ile (ToDoItemData) provider kullandık. Peki aynı yere birden fazla classı provider olarak kullanmamız gerekseydi ne yapacaktık ?

O zaman da MultiProvider kullanmamız gerekecekti. Uygulamamızda örneği olmadığı için bu örneği Flutter Dokümantasyonlarında göstereceğim;

MultiProvider

Gördüğünüz gibi ufak bi yazım farklılığı olsa da önceki örneğimizden çok farklı değil.

Gelelim Consumer in ne olduğuna… Consumer widgetı kullanılan verilerin her değiştiğinde sarmalandığı widgetı değiştirmektedir. Bunu en başta kullandığımız provider sınıfı ile (ToDoItemData) iletişim içinde kalarak yapar.Uygulamamızda ise şöyle kullanılmaktadır;

Consumer

Consumer kullanıyorsak <...> ifadesini de kullanmak zorundayız.Bu ifade provider paketine hangi türden verilerle uğraşacağmızı bildirmektedir.

Consumer widgetı sadece builder özelliğine ihtiyaç duyar. Üç adet değişken almaktadır. context tüm yeniden widget inşasında kullandığınız değişkendir, data isimlendirmesi tamamen bize ait olan bir değişkendir ve <...> ifadesinin içinde yazdığımız classtan gelen verileri temsil etmektedir.child ise modelimiz değiştiğinde değişmeyen bir widgetımız varsa kullanmamız gereken bir özelliktir.

Yazının başından beri parent widgetlardan child widgetlara bilgi aktarımı yapmaktayız. Peki kullanıdğımız veriler üzerinde değişikliği child widgetlarda nasıl yapacağız ? Hatırlarsanız ToDoItemData classının içinde notifyListeners() metodunu içeren, veri ekleme, silme, güncelleme gibi fonksiyonlarımız vardı. İşte bunları kullanacağız fakat bu işi bir class içinde başka bir classın metodlarını kullanmaktan bir miktar farklı yapacağız. Bu demek oluyor ki sıra Provider.of kullanımını incelemeye geldi.

Uygulama Ekran Görüntüsü

Yukarıda yapmakta olduğumuz uygulamanın bir görüntüsü mevcut. Yapılacak görev kartlarında görevi yapıldı olarak işaretleme, erteleme ve kartı kaydırarak silme seçenekleri mevcut. Bu işlemleri Provider.of kullanmadan yaparsak kullanıcının anlık olarak değiştirdiği, uygulamayı kapattığında ya da ekranı değiştirdiğine her şeyin eskiye döndüğü bir kullanıma ulaşmış oluruz. Biz istiyoruz ki yapılan değişiklik ile veriyi sakladığımız classı yapmak istediğimiz değişiklikten haberdar edelim ve bizim için bu değişikliği yapmasını sağlayalım. Bu işlemi aşağıdaki gibi yapmaktayız.

Erteleme ve yapıldı olarak işaretleme butonlarının nasıl çalıştığını görmekteyiz. Dilersenin gelin erteleme butonun nasıl çalıştığını inceleyelim.

Kullanığımız bir şart koşulunda Provider.of<ToDoItemData>(context,listen:false).toDoItems[widget.index].situation ifadesiyle biz ToDoItemData classına git, içindeki toDoItems dizise ulaş mevcut ekrandaki index değerinde bulunan elamanının situation durumunu bana getir demekteyiz. Stiuation durumunu kontrol ettiken sonra Provider.of<ToDoItemData>(context,listen:false).changeSituationLater(widget.index) ifadesi ile ToDoItemData classındaki changeSituationLater fonksiyonunu çalıştırmaktayız ki o fonksiyonda hatırlarsak şu şekildeydi;

Görüldüğü üzere fonksiyon bir index değeri alıyor. Bu index ile toDoItems dizisindeki değere ulaşıyoruz. toDoItems dizisi içinde ToDoItem tipinde değişkenler tutmaktadır. Fonksiyon içinde bu değerin ait olduğu classta bulunan başka bir changeSituationToLater adlı fonksiyonu çağırıyoruz.

Bu fonksiyon da yukarıda görüldüğü gibi ToDoItem adlı classın situation değerini later olarak değiştirmekte. Bu işlemleri yaptıktan sonra notifyListeners() metodu ile gerekli tüm yerleri verinin değiştiğine dair haber veriyoruz.

Peki Provider.of ifadesinde listen:false değeri ne işe yaramaktadır. Eğer Provider.of ifadesi kullanıldığı yerde veride bir değişiklik yapacaksa listen:false yaparak aslında onun “ben sadece verileri göstermeyeceğim, veriler üzerinde bir değişiklik yapacağım” demesini sağlıyoruz.

Bu ayki yazımın da sonuna gelmiş bulunmaktayım. Buraya kadar okuduğunuz ve gerekli konularda aşağıda bırakacağım bağlantılar ile bana geri dönüş sağladığınız için şimdiden teşekkür ederim. Önümüzdeki aylarda farklı konularda buluşmak üzere.

Proje Kodları:

https://github.com/leventsrr/to_do_with_flutter

Twitter:

https://twitter.com/LeventSrr

--

--