My Application Development Process with Flutter: How Did I Go From Zero to Broadcast?

 

My journey into the world of mobile app development actually started with a great discovery: Flutter. At first, I set out thinking, “What can I do with such a popular framework?”. Today, I have several apps both published and in development. In this article, I would like to share with you my process of developing a Flutter app from scratch and what I experienced during this process. Especially my English teaching app for children was a big turning point for me in this process. 

1. First Introducing Flutter: Why Flutter?

Flutter ile ilk tanıştığımda, mobil uygulama geliştirmeye oldukça yeniydim. When I first met Flutter, I was quite new to mobile app development. I had worked with languages like C# and SQL before, but the mobile world was an unknown area for me. As a result of my research, I learned that Flutter offers the opportunity to develop apps for both iOS and Android platforms with a single code base, which was a great advantage for beginners like me. Getting fast results and having the support of a large community played an important role in my choice of Flutter. 

2. My First Project: English Teaching Practice, Penguin Academy



My first project at Flutter was an app that aimed to teach English to children and have fun. The app aimed to teach words to children with simple visual cards and audio pronunciations. I had a lot of questions when I started this project: What kind of user interface should I design? How will I manage the data? But thanks to Flutter's extensive libraries and easy-to-use tools, I was able to move forward step by step. 

The biggest challenge I faced during this process was dynamic data management. Categorized word cards and audio files were central to the application. It took me a while to figure out data management with Flutter's widgets like ListView and GridView. But in the end, I created an interface that was both performant and user-friendly. 

3. Preparation for Publication: Installing Apps on Google Play

After developing the app, it was time to get it ready for release. At first, I had no idea how to upload the app to the Google Play Store. But step by step, I packaged and uploaded the app on my husband's Google Play developer account, and learned a few things along the way:  

  • App Icon and Promotional Images: Visuals are very important to attract users' attention on Google Play. I prepared professional looking icons and screenshots.
  • App Description: It is very important to explain what the app does in a simple but impressive language. Here, I made it clear which features users will benefit from.

After these steps, my app is finally live! The excitement of releasing a mobile app for the first time was really indescribable. The initial feedback gave me a new perspective on the development of the app. 

And here is the result :

https://play.google.com/store/apps/details?id=com.cemnamak.flash_cards&pcampaignid=web_share

I would be very happy for your comments and feedback.

4. User Feedback and Improvements

After releasing it, I realized that the real work starts now. As users downloaded the app, feedback started coming in. In line with this feedback, I continuously updated the app. In particular, expanding the vocabulary categories and adding more sounds and visuals that would be interest to children was an important update step.

The next step was to add a stories section, where I wrote stories on topics of interest to children, supported them with visuals, and made adjustments such as screen orientation to ensure easy readability.

I also encountered performance issues - the dynamically loaded data could sometimes slow down the app. But thanks to Flutter's strong community and platforms like Stack Overflow, I had no trouble solving these problems.

5. Other Projects and Future Plans

After my English teaching app, I started working on new projects, one of which was a recipe app for babies. In this project, I used Flutter to design dynamic data loading and category-based browsers. This app is still in development and I plan to release it soon.

What I've learned on my app development journey with Flutter has taught me a lot, both technically and in terms of problem solving skills. Learning something new and improving myself in every project continues to motivate me.

I hope my Flutter journey will inspire those who are looking for direction. Thank you for reading this far. 

Don't forget to subscribe and leave your e-mail address to be informed about my new publications.

Thank you very much.

Selin.

Flutter ile Uygulama Geliştirme Sürecim: Sıfırdan Yayına Nasıl Ulaştım?

 

Mobil uygulama geliştirme dünyasına adım atmam, aslında büyük bir keşifle başladı: Flutter. İlk başta, “Bu kadar popüler olan bu çerçeveyle neler yapabilirim?” diye düşünerek yola çıktım. Bugün ise, hem yayınladığım hem de geliştirme aşamasında olan birkaç uygulamam var. Bu yazıda, sıfırdan bir Flutter uygulaması geliştirme sürecimi ve bu süreçte yaşadıklarımı sizlerle paylaşmak istiyorum. Özellikle çocuklar için geliştirdiğim İngilizce öğretme uygulamam bu süreçte benim için büyük bir dönüm noktasıydı.

1. Flutter ile İlk Tanışma: Neden Flutter?

Flutter ile ilk tanıştığımda, mobil uygulama geliştirmeye oldukça yeniydim. Daha önce C# ve SQL gibi dillerle çalışmıştım, ama mobil dünyası benim için bilinmeyen bir alandı. Araştırmalarım sonucunda, Flutter’ın tek bir kod tabanıyla hem iOS hem de Android platformlarında uygulama geliştirebilme imkânı sunduğunu öğrendim. Bu da, benim gibi yeni başlayanlar için büyük bir avantajdı. Hızlı sonuçlar almak ve geniş bir topluluğun desteğine sahip olmak, Flutter’ı seçmemde önemli bir rol oynadı.

2. İlk Projem: İngilizce Öğretme Uygulaması


Flutter’daki ilk projem, çocuklara İngilizce öğretmeyi hedefleyen bir uygulamaydı. Uygulama, basit görsel kartlar ve sesli telaffuzlarla çocuklara kelimeleri öğretmeyi amaçlıyordu. Bu projeye başlarken kafamda birçok soru işareti vardı: Nasıl bir kullanıcı arayüzü tasarlamalıyım? Verileri nasıl yöneteceğim? Ancak, Flutter’ın geniş kütüphaneleri ve kullanımı kolay araçları sayesinde adım adım ilerleyebildim.

Bu süreçte karşılaştığım en büyük zorluk, dinamik veri yönetimiydi. Kategorilere göre ayrılmış kelime kartları ve ses dosyaları, uygulama için merkezi bir rol oynuyordu. Flutter’ın ListView ve GridView gibi widget’larıyla veri yönetimini çözmem biraz zaman aldı. Ancak sonunda, hem performanslı çalışan hem de kullanıcı dostu bir arayüz oluşturdum.

3. Yayına Hazırlık: Google Play’e Uygulama Yükleme

Uygulamayı geliştirdikten sonra sırada onu yayına hazırlamak vardı. İlk başta, uygulamayı Google Play Store’a nasıl yükleyeceğim konusunda hiçbir fikrim yoktu. Ama adım adım ilerleyerek eşimin Google Play geliştirici hesabı üzerinde uygulamayı paketleyip yükledim. Bu süreçte dikkat edilmesi gereken birkaç şey öğrendim:

  • Uygulama İkonu ve Tanıtım Görselleri: Google Play’de kullanıcıların dikkatini çekmek için görsellerin önemi çok büyük. Profesyonel görünümlü ikonlar ve ekran görüntüleri hazırladım.
  • Uygulama Tanımı: Uygulamanın ne yaptığını basit ama etkileyici bir dille açıklamak çok önemli. Burada, kullanıcıların hangi özelliklerden faydalanacağını açıkça belirttim.

Bu adımlardan sonra, nihayet uygulamam yayında! İlk kez bir mobil uygulamayı yayınlamanın verdiği heyecan gerçekten tarif edilemezdi. Gelen ilk geri bildirimler sayesinde uygulamayı geliştirme konusunda yeni bir perspektif kazandım.

Ve işte sonuç :

https://play.google.com/store/apps/details?id=com.cemnamak.flash_cards&pcampaignid=web_share

Yorum ve geri bildirimleriniz beni çok mutlu eder.

4. Kullanıcı Geri Bildirimleri ve Geliştirmeler

Yayınladıktan sonra fark ettim ki, asıl iş şimdi başlıyor. Kullanıcılar uygulamayı indirdikçe, geri bildirimler de gelmeye başladı. Bu geri bildirimler doğrultusunda uygulamayı sürekli olarak güncelledim. Özellikle, kelime kategorilerini genişletmek ve çocukların ilgisini çekebilecek daha fazla ses ve görsel eklemek, önemli bir güncelleme aşamasıydı.

Bir sonraki adımda ise hikayeler bölümü ekledim. Çocukların ilgisini çekecek konularda hikayeler yazarak görsellerle destekledim ve kolay okunurluk sağlamak adına ekran yönü gibi düzenlemeler çalıştım.

Ayrıca, performans sorunlarıyla da karşılaştım. Dinamik olarak yüklenen veriler zaman zaman uygulamayı yavaşlatabiliyordu. Ancak Flutter’ın güçlü topluluğu ve Stack Overflow gibi platformlar sayesinde bu sorunları çözmekte zorlanmadım.

5. Diğer Projeler ve Gelecek Planları

İngilizce öğretme uygulamamdan sonra, yeni projeler üzerinde çalışmaya başladım. Bunlardan biri de bebekler için yemek tarifleri uygulamasıydı. Bu projede de Flutter’ı kullanarak dinamik veri yükleme ve kategori bazlı tarayıcılar tasarladım. Hala geliştirme sürecinde olan bu uygulamayı da yakında yayınlamayı planlıyorum.

Flutter ile uygulama geliştirme yolculuğumda öğrendiklerim, bana hem teknik açıdan hem de problem çözme becerisi açısından çok şey kattı. Her projede yeni bir şey öğrenmek ve kendimi geliştirmek beni motive etmeye devam ediyor.

Umarım Flutter yolculuğum kendisine yön arayanlara ilham olur. Buraya kadar okuduğunuz için teşekkür ederim.

Yeni yayınlarımdan haberdar olmak için abone olup, mail adresinizi bırakmayı unutmayın.

Teşekkürler.

Selin.

What Is Riverpod? Here’s What I Learned from Different Resources

 

Hello everyone.

I’ve been obsessed with StateManagement in Flutter lately, because as my knowledge of Flutter increases, I’m attempting to make more comprehensive projects. However, I always get stuck when it comes to moving, storing and retrieving data. I’ve tried to use the provider package a bit before, but provider is not enough for the application I’m working on right now. So when my research pointed out that Riverpod can be used in more extensive projects than provider, I started working on it.

And now I’m here to compile the information I got first from the documentation and then from different sources. I hope I will inspire you. Let’s get started.

What is Riverpod?

I hope my first note about Riverpod will be a kind of icebreaker. Riverpod is an anagram of provider, a different arrangement of the same letters. :)

Let’s see what it is. Riverpod is a modern and flexible state management solution in Flutter. It’s more secure, independent and testable than traditional approaches, and with it we can manage state in our application more effectively.

So why do we need StateManagement? I would like to talk a little bit about this before going into the details of Riverpod.

Why State Management?

Imagine we are building an application with many different screens and widgets. And some of them may need to access the same state, such as the productState. For example, in the tree diagram below, the Home Screen and the Shopping Cart widget may both need the same productState.

Once a state is defined in the Home Screen, to update it we need to create a function or state within that widget and then pass that function or state up to the shopping cart widget. When we do this, the widget tree is rebuilt to reflect this state change. This is a relatively simple and common scenario up to a point. But another common scenario is having to use the operation in more than one place, like this one, where we define the state at the vertex of the tree and then pass it through the widgets to other places where it is needed. When the latter scenario becomes more common in practice, it can lead to a bit messy and hard to maintain code, I know because it happened to me :). This is where a state management solution simplifies things for us.

As I show in the diagram below, once we define the function or state with the provider at the top, we can call it wherever we want without going through the entire hierarchy in the widget tree.

Now that we have talked about what riverpod is and why State Management is necessary, we can start using riverpod.

Installation

First of all, as in every package usage, we install our package in our project.

flutter pub add flutter_riverpod

And then it is added to the pubspec.yaml file with whatever the current version is as follows.

dependencies:
flutter_riverpod: ^2.5.3

We import it to the page we will use as follows.

import 'package:flutter_riverpod/flutter_riverpod.dart';

Usage

We wrap the runApp function in the main method of our project with ProviderScope. This is used to keep the states of all created providers.

void main() {
runApp(
const ProviderScope(
child: MyApp(),
),
);
}

By the way, provider in software literally means an object that covers a state and allows this state to be listened to. And it means the same thing in all StateManagement solutions and is simply used with the same logic.

At this point I want to write a simple example of a provider object. Like every function or property definition, provider also has a return type. In this example, this provider returns a String.

final helloRiverpodProvider = Provider<String>((ref) {
return 'Hello Riverpod';
});

We write this provider object as a global variable outside all methods and widgets in order to be able to access it from anywhere on the page, in all widgets we will write. Now let’s see how to use this global variable.

Using Provider Object in Widget

1- With ConsumerWidget

class HelloRiverpodWidget extends ConsumerWidget { 
const HelloRiverpodWidget({super.key});

@override
Widget build(BuildContext context, WidgetRef ref) {
return Container();
}
}

The widget we create here is extended from Consumer Widget, not from Stateless or Stateful Widget. ConsumerWidget works like Stateless Widget. In the build method, the WidgetRef parameter must be present as well as the BuildContext parameter.

We read the variable defined as a global variable with the ref.watch method and use it by assigning it to a separate variable in the widget.

class HelloRiverpodWidget extends ConsumerWidget {
const HelloRiverpodWidget({super.key});

@override
Widget build(BuildContext context, WidgetRef ref) {
final helloRiverpod = ref.watch(helloRiverpodProvider);
return Text(helloRiverpod);
}
}

2- With Consumer

When we wrap the whole Scaffold with ConsumerWidget, the whole Scaffold is refreshed every time there is a change in the Provider object. This can mean extra performance issues. Instead we can wrap only the Widget containing the Provider object with Consumer.

class HelloRiverpodWidget extends StatelessWidget {
const HelloRiverpodWidget({super.key});

@override
Widget build(BuildContext context) {
return Scaffold(
body: Consumer(
builder: (context, ref, child) {
final helloRiverpod = ref.watch(helloRiverpodProvider);
return Text(helloRiverpod);
},
),
);
}
}

Here we need to configure the builder well, which is required when we create a consumer. For this reason, it is more detailed than ConsumerWidget.

Instead, if we configure our widgets to be reusable and break them into small pieces, we can continue to use ConsumerWidget and minimize the performance problem related to rebuild.

3- With ConsumerStatefulWidget

I mentioned that ConsumerWidget is the counterpart of StatelessWidget. In cases where we need to use StatefulWidget, we can use ConsumerStatefulWidget as the counterpart.

Here we have two methods to call the provider object. The first is to call it in initState().

@override
void initState() {
super.initState();
final helloRiverpod = ref.read(helloRiverpodProvider);
print(helloRiverpod);
}

The other method is to call it in the classic widget tree.

class HelloRiverpodStful extends ConsumerStatefulWidget {
const HelloRiverpodStful({super.key});

@override
ConsumerState<ConsumerStatefulWidget> createState() => _HelloRiverpodStfulState();
}

class _HelloRiverpodStfulState extends ConsumerState<HelloRiverpodStful> {

@override
Widget build(BuildContext context) {
final helloRiverpod = ref.watch(helloRiverpodProvider);
return Text(helloRiverpod);
}
}

If we use the WidgetRef ref in the build method, we call it with watch(), if we use it in one of the other methods, we call it with read(). Both cases return a value. I will compare these two methods in more detail below.

WidgetRef ref is evaluated as an argument in Consumer or ConsumerWidget and as a property in ConsumerState.

WidgetRef is the object that allows widgets like BuildContext to interact with provider objects. BuildContext allows to access ancestor widgets in the widget tree. Like Theme.of(context) or MediaQuery.of(context). WidgetRef allows accessing any provider in the application. Because all Riverpod providers are global.

ref.watch() vs ref.read()

In the build method, we use ref.watch() to observe the state of a provider object and rebuild it if it changes.

To read the state of a provider object only once (like initState) we use ref.read().

In the onPressed callback method of a button we use ref.read(), not ref.watch.

Sometimes we want to show SnackBar or alertDialog when a provider state changes. We can do this by calling the ref.listen() method inside the build method.

ref.listen() provides a callback when the provider object changes, not when build is called. So it can also be used to run asynchronous code.

In my article, I shared my Riverpod notes that I researched and learned from different sources. Before I conclude, I would like to mention a plugin for vscode: Flutter Riverpod Snippets.

This plugin speeds up writing code by automatically completing frequently used Riverpod code snippets. For example, you can quickly add basic code for common Riverpod constructs like Provider, StateNotifier, ConsumerWidget, etc. so you don’t have to write from scratch every time. It also helps you minimize bugs.

I continue to learn about Riverpod, because I can see that it is a vast subject, like the general software world description. I will write about what I learn in a second article in the future.

Error-free code to all of us.

Thank you for reading.

I would appreciate if you subscribe to be informed about my new articles.

Selin.

Riverpod Nedir? İşte Farklı Kaynaklardan Öğrendiğim En Önemli Bilgiler

 

Herkese merhaba.

Bu ara Flutter’da StateManagement konusuna kafayı takmış durumdayım. Çünkü Flutter konusunda bildiklerim arttıkça daha kapsamlı projeler yapma girişiminde bulunuyorum. Ancak her defasında veri taşıma, saklama, çağırma konusu geldiğinde tıkanıp kalıyorum. Daha önce provider paketini biraz kullanmayı denedim ancak şu an üzerinde çalıştığım uygulamam için provider yeterli olmuyor. Bunun için araştırmalarım Riverpod’un provider’dan daha kapsamlı projelerde kullanılabileceğine işaret edince başladım üzerinde çalışmaya.

Ve şimdi buraya da önce dökümantasyondan sonra da farklı kaynaklardan edindiğim bilgileri derlemeye geldim. Umarım ilham olurum. Haydi başlayalım.

Riverpod nedir?

Riverpod ile ilgili ilk notumun bir çeşit “icebreaker” olmasını umuyorum. Riverpod, provider’ın anagramıymış, aynı harflerin farklı dizilimi :)

Gelelim ne olduğuna. Riverpod, Flutter’da modern ve esnek bir durum yönetimi (state management) çözümü. Geleneksel yaklaşımlara göre daha güvenli, bağımsız ve test edilebilir bir yapı sunuyor ve bizde onunla uygulamamızdaki durumu daha etkili bir şekilde yönetebilir oluyoruz.

Peki neden StateManagement’a ihtiyacımız var? Riverpod’un detaylarına geçmeden önce biraz bundan bahsetmek istiyorum.

Neden Durum Yönetimi(State Management)?

Birçok farklı ekran ve widget içeren bir uygulama yaptığımızı düşünün. Ve bunlardan bazılarının, aynı state’e -productState gibi- erişmesi gerekebilir. Örneğin aşağıdaki ağaç diyagramında Ana Ekran ve Alışveriş Sepeti widget’ının her ikisi de aynı productState’e ihtiyaç duyabilir.

State Ana Ekran widget’ında tanımlandığında, bunu güncellemek için bu widget içinde bir fonksiyon veya state oluşturmamız ve ardından bu fonksiyon veya state’i alışveriş sepeti widget’ına kadar iletmemiz gerekir. Bunu yaptığımızda, widget ağacı bu durum değişikliğini yansıtacak şekilde yeniden oluşturulur. Bu bir aşamaya kadar nispeten basit ve yaygın bir senaryo. Ancak yaygın olan bir başka senaryo da bunun gibi durumu ağacın tepe noktasında tanımladığımız ve daha sonra widget’lar aracılığıyla ihtiyaç duyulan diğer yerlere aktardığımız operasyonu birden fazla yerde kullanmak durumunda kalmak. İkinci senaryo uygulamada daha yaygın hale geldiğinde, biraz dağınık ve bakımı zorlaşan kodlara yol açabiliyor, başıma geldiği için biliyorum :). İşte bu noktada bir durum yönetimi çözümü bizim için işleri basitleştiriyor.

Aşağıdaki diagramda gösterdiğim gibi provider ile fonksiyon ya da state’i bir kez en tepe noktasında tanımladıktan sonra widget ağacında tüm hiyerarşiyi gezmeden istediğimiz yerde çağırabiliyoruz.

Riverpod’un ne olduğu ve State Management’ın neden gerekli olduğunu konuştuğumuza göre riverpod’u kullanmaya başlayabiliriz.

Kurulumu

Öncelikle her paket kullanımında olduğu gibi paketimizi projemize install ediyoruz.

flutter pub add flutter_riverpod

Ve ardından pubspec.yaml dosyasına aşağıdaki gibi güncel versiyonu ne ise onunla ekleniyor.

dependencies:
flutter_riverpod: ^2.5.3

Kullanacağımız sayfaya ise aşağıdaki gibi import ediyoruz.

import 'package:flutter_riverpod/flutter_riverpod.dart';

Kullanımı

Projemizin main metodu içindeki runApp fonksiyonunu ProviderScope ile sarıyoruz. Bu oluşturulan tüm provider’ların state’lerini tutmaya yarar.

void main() {
runApp(
const ProviderScope(
child: MyApp(),
),
);
}

Bu arada provider yazılımda kelime anlamı olarak bir state’i kapsayan ve bu state’in dinlenmesini sağlayan nesne demek. Ve tüm StateManagement çözümlerinde aynı anlama geliyor ve basitçe aynı mantıkla kullanılıyor.

Bu noktada basit bir provider nesnesi örneği yazmak istiyorum. Her fonksion ya da property tanımlaması gibi provider’ın da bir dönüş türü oluyor. Vereceğim örnekte bu provider bir String döndürüyor.

final helloRiverpodProvider = Provider<String>((ref) {
return 'Hello Riverpod';
});

Bu provider nesnesine sayfanın her yerinden, yazacağımız tüm widget’lar içerisinden ulaşabilmek için global bir değişken olarak tüm metot ve widget’ların dışına yazıyoruz. Şimdi bu tanımladığımız global değişkeni nasıl kullanacağımıza bakalım.

Provider Nesnesinin Widget İçerisinde Kullanımı

1- ConsumerWidget ile

class HelloRiverpodWidget extends ConsumerWidget { 
const HelloRiverpodWidget({super.key});

@override
Widget build(BuildContext context, WidgetRef ref) {
return Container();
}
}

Burada oluşturduğumuz widget Stateless veya Stateful Widget’tan değil, Consumer Widget’tan extend olur. ConsumerWidget Stateless Widget gibi çalışır. build metodu içerisinde BuildContext parametresinin yanısıra WidgetRef parametresi de bulunmak zorundadır.

ref.watch metoduyla global variable olarak tanımlanan değişkeni okuyup widget içerisinde ayrı bir değişkene atayarak kullanıyoruz.

class HelloRiverpodWidget extends ConsumerWidget {
const HelloRiverpodWidget({super.key});

@override
Widget build(BuildContext context, WidgetRef ref) {
final helloRiverpod = ref.watch(helloRiverpodProvider);
return Text(helloRiverpod);
}
}

2- Consumer ile

ConsumerWidget ile tüm Scaffold’u sarmaladığımızda Provider nesnesinde her değişiklik olduğunda tüm Scaffold yenilenir. Bu da ekstra performans sorunu demek olabilir. Bunun yerine yalnızca Provider nesnesi içeren Widget’ı Consumer ile sarabiliriz.

class HelloRiverpodWidget extends StatelessWidget {
const HelloRiverpodWidget({super.key});

@override
Widget build(BuildContext context) {
return Scaffold(
body: Consumer(
builder: (context, ref, child) {
final helloRiverpod = ref.watch(helloRiverpodProvider);
return Text(helloRiverpod);
},
),
);
}
}

Burada consumer oluşturduğumuzda required olan builder’ı iyi yapılandırmak gerekir. Bu sebeple ConsumerWidget’tan daha detaylıdır.

Bunun yerine widget’larımızı yeniden kullanılabilecek şekilde yapılandırır, küçük parçalara ayırırsak ConsumerWidget’ı kullanmaya devam edebilir, rebuild ile ilgili performans sorununu en aza indirebiliriz.

3- ConsumerStatefulWidget ile

ConsumerWidget’ın StatelessWidget’ın karşılığı olduğunu söylemiştim. StatefulWidget kullanmamız gereken durumlarda karşılık olarak ConsumerStatefulWidget’ı kullanabiliriz.

Burada provider nesnesini çağırmak için iki yöntemimiz var. Birincisi initState() içerisinde çağırmak.

 @override
void initState() {
super.initState();
final helloRiverpod = ref.read(helloRiverpodProvider);
print(helloRiverpod);
}

Diğer yöntem ise klasik widget ağacı içerisinde çağırmak.

class HelloRiverpodStful extends ConsumerStatefulWidget {
const HelloRiverpodStful({super.key});

@override
ConsumerState<ConsumerStatefulWidget> createState() => _HelloRiverpodStfulState();
}

class _HelloRiverpodStfulState extends ConsumerState<HelloRiverpodStful> {

@override
Widget build(BuildContext context) {
final helloRiverpod = ref.watch(helloRiverpodProvider);
return Text(helloRiverpod);
}
}

WidgetRef ref’i build metodu içerisinde kullanıyorsak watch() ile, diğer metotlardan birinde kullanıyorsak read() ile çağırırız. Her iki durum da değer döndürüyor. aşağıda bu iki metodun karşılaştırmasına daha detaylı şekilde yer vereceğim.

WidgetRef ref, Consumer veya ConsumerWidget içerisinde bir argüman olarak, ConsumerState içerisinde ise property olarak değerlendirilir.

WidgetRef BuildContext gibi widget’ların provider nesneleri ile etkileşime girmesini sağlayan nesne. BuildContext widget ağacındaki ata widget’lara ulaşmayı sağlar. Theme.of(context) veya MediaQuery.of(context) gibi. WidgetRef ise uygulama içindeki herhangi bir provider’a erişmeyi sağlar. Çünkü tüm Riverpod provider’ları globaldir.

ref.watch() vs ref.read()

Build metodu içerisinde bir provider nesnesinin durumunu gözlemlemek ve değişirse yeniden build etmek için ref.watch kullanıyoruz.

Bir provider nesnesinin durumunu yalnızca bir kez okumak için (initState gibi) ref.read kullanıyoruz.

Bir butonun onPressed callback metodu içinde ref.watch değil ref.read kullanıyoruz.

Bazen bir provider durumu değiştiğinde SnackBar veya alertDialog göstermek isteriz. Bunu build metodu içinde ref.listen metodunu çağırarak yapabiliriz.

ref.listen build çağrıldığında değil, provider nesnesi değiştiğinde bir callback sağlar. Bu yüzden asenkron kodu çalıştırmak için de kullanılabilir.

Makalemde farklı kaynaklardan araştırdığım ve öğrendiğim Riverpod notlarımı aktardım. Sonlandırmadan önce vscode için bir eklentiden bahsetmek istiyorum: Flutter Riverpod Snippets.

Bu eklenti, sık kullanılan Riverpod kod parçacıklarını (snippets) otomatik olarak tamamlayıp kod yazmayı hızlandırıyor. Örneğin, ProviderStateNotifierConsumerWidget gibi yaygın Riverpod yapılarının temel kodlarını hızlıca ekleyebiliyorsunuz, böylece her seferinde sıfırdan yazmak zorunda kalmıyorsunuz. Hataları da minimize etmenize destek oluyor.

Ben Riverpod’u öğrenmeye devam ediyorum, zira genel yazılım dünyası tanımlaması gibi, derya deniz bir konu olduğunu görebiliyorum. İlerleyen zamanlarda yeni öğrendiklerimi de ikinci bir makalede yazarım.

Hepimize hatasız kodlar.

Okuduğunuz için teşekkürler.

Yeni makalelerimden haberdar olmak için abone olursanız memnun olurum.

Selin.