Bloc ile state yönetimine giriş, Cubit mantığı #19

Gauloran

Global Moderatör
7 Tem 2013
8,188
638
ffsf.png

Bu konuda Bloc ile state yönetiminden bahsedeceğim. Öncelikle Bloc yapısını anlamak istiyorsak Cubit mantığını kavramamız gerekir. Örnek olarak bir diziden random isim çeken bir buton örneği ve çekilen ismin state olarak UI'a yansıtılmasını yapacağız. Daha fazla örneği konunun devamında ele alacağız şimdilik başlayalım. Öncelikle terminali açın ve projeye bloc'u ekleyelim.

0*LfjQluswDBDuKUSq


flutter pub add bloc ve flutter pub add flutter_bloc ayrı ayrı yazıp ekleyebilirsiniz. bloc olan temel bloc yapısını içermekte ve diğeri de UI kompanentleri ile etkileişim sağlayan çeşitli yapılar barındırmakta. Normalde bu yapacağımız örnekte kullanmayacağız ama aynı projede silip silip farklı örnekler yapacağımız için şimdiden ekleyelim.

Kod:
const names = ['isim1', 'isim2', 'isim3'];

isimler listemizi bu şekilde oluşturuyoruz ve Iterable'lara bir extension yazalım bu extension ile bir fonksiyon kazandırmayı amaçlıyorum bu fonksiyon da rastgele listeden index seçecek ve o indeksteki elemanı getirecek. Bunun için de dart math'i import etmemiz gerek.

Kod:
extension RandomElement<T> on Iterable<T> {
    T getRandomElement()=> elementAt(math.Random().nextInt(length));
}

extensionımızı yazdık. getRandomElement diye adını verdik rastgele eleman çekmeye yarayacak. Burada elementAt fonksiyonunu da kullanmış olduk bu fonksiyon ilgili indeksteki elemanı vermeye yarayacak Random sınıfı sayesinde de dizinin uzunluğu ile sınırlandırdığımız bir random indeks üretecek.

Şimdi Cubit kavramına gelelim. Cubit sınıfımızı oluşturuyoruz

0*uSCxzuvQZl9ChEZt.png


Kod:
class NamesCubit extends Cubit<String?> {
    NamesCubit():super(null);
}

Cubitlerin state leri vardır yönettiği değer anlamına geliyor yani biz cubitler sayesinde değerleri yönetebiliyoruz. <> İçerisine yöneteceğimiz veri türünü girdik String? şeklinde. Başlangıç değeri bekler yani bir nevi initialState. Onu da null verdik yöneteceğimiz veri türü nullable zaten yani sıkıntımız yok. Cubitin mantığı şu şekilde çalışır yeni state'i bildireceğimiz zaman emit kullanıyoruz.

cubit içerisine şöyle bir fonksiyon yazabiliriz

Kod:
void pickRandomName(){
    emit(names.getRandomElement());
}

Streamlerle benzer mantıkta aslında cubitler. Bir üst katman gibi düşünebiliriz. Cubitleri kullanıp initialize edip dispose edebiliriz. Bunun için stful bir widget yapısı kullanabiliriz. Bu örnek basit olacak diye StreamBuilder kullanacağız. Devam eden örnekler biraz daha karmaşık olacak. Stful bir widget oluşturun adı HomePage olsun. Bu widget yapısına initState ve dispose ekleyin. Vscode size yardımcı olur birkaç harf yazdığınız gibi direkt çıkartır zaten.

Kod:
@override
initState(){
    super.initState();
    cubit = NamesCubit();
}

dispose(){
 cubit.close();
 super.dispose();
}

devam edelim. Tabii class _HomePageState extends State<HomePage> scope'unun hemen altında şu şekilde bir tanımlama yapmayı unutmayın.

late final NamesCubit cubit;

daha sonra StreamBuilder kullanarak StreamBuilder<YönetilecekVeriTürü> şeklinde kullanım yapıyoruz tasarımın body kısmında.

Kod:
StreamBuilder<String?> {
    stream: cubit.stream,
    builder: (context, snapshot){
        final button = TextButton(
            onPressed: (){
                cubit.pickRandomName();
            }
            child: const Text('random isim cek')
        )
    }
}

Ads-z.png

Bu StreamBuilder devamında bir switch case yapısı kullanarak da snapshot.connectionState'i kontrol ederek örneğin case ConnectionState.none: ise şunu return et yok efendim .waiting ise şunu return et active ise (cubitimiz kullanılıyorsa şunu return et) şeklinde çeşitli return etmeler yapabiliyoruz.

Cubit aslında stateleri bir stream akışı gibi tutar bu nedenle cubit.stream diyerek streamini verebiliyoruz StreamBuilder'ın. devamında ise builder ister builder context ve snapshot alır snapshot'un datası zaten verinin kendisidir. Yani bu switch yapısında Bir Column döndürerek içerisinde

Text(snapshot.data ?? '') diye verebiliriz göstermek için. Böylece butona tıkladığımızda cubit.pickRandomName(); fonksiyonu çalışır.

Bu fonksiyon getRandomElement fonksiyonunu çalıştırır ve GetRandomElement fonksiyonu rastgele index oluşturup elementAt fonksiyonu yardımıyla listeden rastgele isim çeker. Ve bu veriyi emit eder. Bu yöneteceğimiz veri zaten.

Temel mantık bu şemada


blobid1637296666932.png


Böylece butona tıkladığınızda değişiklik anlık olarak gelir Cubit mantığıyla state yönetimi bu şekilde yapılabilir.


Cubit mantığını anlamak adına incelemeniz gereken bir takım kodlar bırakıyorum:

Kod:
// [CounterCubit], 'int' tipinde bir state'i bulunan bir Cubit sınıfıdır.
class CounterCubit extends Cubit<int>{

  // [CounterCubit] sınıfının başlangıç durumu '0' olarak belirlenmiştir.
  CounterCubit() : super(0);

  // 'state' değişkeni, [CounterCubit] sınıfının state'ini temsil eder.
  // 'emit' metodu, [CounterCubit] sınıfının state'ini güncellemek için kullanılır.

  // [increment] fonksiyonu, [CounterCubit] sınıfının state'ini arttırmak için kullanılır.
  void increment() => emit(state + 1);

  // [decrement] fonksiyonu, [CounterCubit] sınıfının state'ini azaltmak için kullanılır.
  void decrement() => emit(state - 1);
 
}

Kod:
void main() {

  /// `CounterCubit` sınıfından bir instance oluşturulur.
  final cubit = CounterCubit();

  /// oluşturduğumuz Cubit' in state'ine `state` ile erişilir.
  print(cubit.state); // 0

  /// Cubit' e interaksiyon/olay tetikliyerek state'ini değiştirebiliriz.
  cubit.increment();

  /// Yeni state'imize erişebiliriz.
  print(cubit.state); // 1

  /// `cubit` artık kullanılmıyorsa kapatılmalıdır.
  cubit.close();
}

Kod:
class CounterCubit extends Cubit<int> {
  CounterCubit() : super(0);

  void increment() => emit(state + 1);

  @override
  void onChange(Change<int> change) {
    super.onChange(change);
    print(change);
  }

  @override
  void onError(Object error, StackTrace stackTrace) {
    print('$error, $stackTrace');
    super.onError(error, stackTrace);
  }
}

Kod:
class MyBlocObserver extends BlocObserver {
  @override
  void onCreate(BlocBase bloc) {
    super.onCreate(bloc);
    print('onCreate -- ${bloc.runtimeType}');
  }

  @override
  void onChange(BlocBase bloc, Change change) {
    super.onChange(bloc, change);
    print('onChange -- ${bloc.runtimeType}, $change');
  }

  @override
  void onError(BlocBase bloc, Object error, StackTrace stackTrace) {
    print('onError -- ${bloc.runtimeType}, $error');
    super.onError(bloc, error, stackTrace);
  }

  @override
  void onClose(BlocBase bloc) {
    super.onClose(bloc);
    print('onClose -- ${bloc.runtimeType}');
  }
}

Bu kısım Cubit mantığını anlamak adına önemli bir adımdı. Bir sonraki konuda Bloc yapısına daha karmaşık örneklerle devam edeceğiz. 2 adet JSON dosyası olacak ve bu JSON dosyalarını Bloc yapısını kullanarak bu jsonlardan nesne üretip UI üzerinde kullanacağız ve state'i yöneteceğimiz bir örnek olacak.

bkz. serinin diğer konuları:

0'dan İleri Seviyeye Mobil Uygulama Geliştirme Eğitimi Veriyorum #1
0'dan İleri Seviyeye Mobil Uygulama Geliştirme Eğitimi Veriyorum #2
0'dan İleri Seviyeye Mobil Uygulama Geliştirme Eğitimi Veriyorum #3
0'dan İleri Seviyeye Mobil Uygulama Geliştirme Eğitimi Veriyorum #4
0'dan İleri Seviyeye Mobil Uygulama Geliştirme Eğitimi Veriyorum #5
0'dan İleri Seviyeye Mobil Uygulama Geliştirme Eğitimi Veriyorum #6
0'dan İleri Seviyeye Mobil Uygulama Geliştirme Eğitimi Veriyorum #7
0'dan İleri Seviyeye Mobil Uygulama Geliştirme Eğitimi Veriyorum #8
0'dan İleri Seviyeye Mobil Uygulama Geliştirme Eğitimi Veriyorum #9
0'dan İleri Seviyeye Mobil Uygulama Geliştirme Eğitimi Veriyorum #10
0'dan İleri Seviyeye Mobil Uygulama Geliştirme Eğitimi Veriyorum #11
0'dan İleri Seviyeye Mobil Uygulama Geliştirme Eğitimi Veriyorum #12
0'dan İleri Seviyeye Mobil Uygulama Geliştirme Eğitimi Veriyorum #13
0'dan İleri Seviyeye Mobil Uygulama Geliştirme Eğitimi Veriyorum #14
0'dan İleri Seviyeye Mobil Uygulama Geliştirme Eğitimi Veriyorum #15
Flutter & Dart Fundamentals | Örnek Quiz Uygulaması #16
Flutter uygulamalarında debugging mantığı #17
Flutter & Dart widget tree, element tree, render tree #18
 
Üst

Turkhackteam.org internet sitesi 5651 sayılı kanun’un 2. maddesinin 1. fıkrasının m) bendi ile aynı kanunun 5. maddesi kapsamında "Yer Sağlayıcı" konumundadır. İçerikler ön onay olmaksızın tamamen kullanıcılar tarafından oluşturulmaktadır. Turkhackteam.org; Yer sağlayıcı olarak, kullanıcılar tarafından oluşturulan içeriği ya da hukuka aykırı paylaşımı kontrol etmekle ya da araştırmakla yükümlü değildir. Türkhackteam saldırı timleri Türk sitelerine hiçbir zararlı faaliyette bulunmaz. Türkhackteam üyelerinin yaptığı bireysel hack faaliyetlerinden Türkhackteam sorumlu değildir. Sitelerinize Türkhackteam ismi kullanılarak hack faaliyetinde bulunulursa, site-sunucu erişim loglarından bu faaliyeti gerçekleştiren ip adresini tespit edip diğer kanıtlarla birlikte savcılığa suç duyurusunda bulununuz.