↑↓ seç · Enter aç · Esc kapat

Mutlu Tekin
Mutlu Tekin
← Yazılar

Bölüm 6 — Konu 26: BLoC/Cubit Pattern (`flutter_bloc`)

4 dk okuma #flutter
Dizi · 26/61 Flutter Türkçe Tutorial
  1. Bölüm 1 — Konu 1: Flutter Nedir, Mimarisi (Widget → Element → RenderObject, Skia/Impeller)
  2. Bölüm 1 — Konu 2: Ortam Kurulumu (Flutter SDK, Android Studio/VS Code, Emulator/Simulator, DevTools'a İlk Bakış)
  3. Bölüm 1 — Konu 3: İlk Proje Yapısı (`pubspec.yaml`, `lib/`, Klasör Mimarisi, `flutter create` Anatomisi)
  4. Bölüm 1 — Konu 4: Hot Reload / Hot Restart Ne Yapıyor, Neden Önemli
  5. Bölüm 2 — Konu 5: "Her Şey Widget'tır" Felsefesi, Widget Ağacı
  6. Bölüm 2 — Konu 6: StatelessWidget vs StatefulWidget + `setState()` Derinlemesine (Rebuild Mekanizması)
  7. Bölüm 2 — Konu 7: Temel Layout — Container, Row, Column, Stack, Padding, Align, Center
  8. Bölüm 2 — Konu 8: Constraint Sistemi — "Constraints Go Down, Sizes Go Up, Parent Sets Position"
  9. Bölüm 2 — Konu 9: `Expanded`, `Flexible`, `Spacer`, Intrinsic Widget'lar
  10. Bölüm 3 — Konu 10: MaterialApp/CupertinoApp, Scaffold, AppBar
  11. Bölüm 3 — Konu 11: `ListView`, `GridView`, `SingleChildScrollView` (+ Builder Pattern)
  12. Bölüm 3 — Konu 12: Text, TextStyle, Icon, Image, Asset Yönetimi
  13. Bölüm 3 — Konu 13: Custom Widget Yazma Prensipleri (Composition Over Inheritance)
  14. Bölüm 3 — Konu 14: Navigator 1.0 — Push/Pop, Named Routes
  15. Bölüm 4 — Konu 15: Form, TextField/TextFormField, GlobalKey<FormState>, Validasyon
  16. Bölüm 4 — Konu 16: Theme Sistemi (ThemeData, ColorScheme)
  17. Bölüm 4 — Konu 17: Responsive & Adaptive Tasarım (MediaQuery, LayoutBuilder, OrientationBuilder, Breakpoint Stratejileri)
  18. Bölüm 5 — Konu 18: Future/Async-Await Flutter Bağlamında, FutureBuilder
  19. Bölüm 5 — Konu 19: `Stream`, `StreamBuilder`
  20. Bölüm 5 — Konu 20: HTTP İstekleri (`http` / `dio` Paketleri)
  21. Bölüm 5 — Konu 21: JSON Serialization (Manuel → `json_serializable`/`freezed`)
  22. Bölüm 5 — Konu 22: Local Storage — `shared_preferences` → `Hive` → `sqflite`/Drift
  23. Bölüm 6 — Konu 23: InheritedWidget ve InheritedModel — "Neden setState Yetmiyor" Sorusunun Cevabı
  24. Bölüm 6 — Konu 24: Provider Paketi
  25. Bölüm 6 — Konu 25: Riverpod (Modern Yaklaşım, Provider'ın Halefi)
  26. Bölüm 6 — Konu 26: BLoC/Cubit Pattern (`flutter_bloc`)
  27. Bölüm 6 — Konu 27: GetX (Tartışmalı Ama Yaygın)
  28. Bölüm 6 — Konu 28: Karşılaştırma — Hangi Projede Hangisi?
  29. Bölüm 7 — Konu 29: Navigator 2.0 (Router, RouteInformationParser, RouterDelegate)
  30. Bölüm 7 — Konu 30: `go_router` Paketi (Pratik ve Modern Çözüm)
  31. Bölüm 7 — Konu 31: Deep Linking
  32. Bölüm 7 — Konu 32: Repository Pattern, Katmanlı Mimari (Data/Domain/Presentation)
  33. Bölüm 7 — Konu 33: Dependency Injection (`get_it`, `injectable`)
  34. Bölüm 7 — Konu 34: Clean Architecture Uyarlaması, SOLID Prensipleri
  35. Bölüm 8 — Konu 35: Implicit Animasyonlar
  36. Bölüm 8 — Konu 36: Explicit Animasyonlar (`AnimationController`, `Tween`, `Curve`)
  37. Bölüm 8 — Konu 37: Hero Animasyonları
  38. Bölüm 8 — Konu 38: `CustomPainter` / `Canvas`
  39. Bölüm 8 — Konu 39: Rive / Lottie Entegrasyonu
  40. Bölüm 9 — Konu 40: Platform Channels
  41. Bölüm 9 — Konu 41: Permission Yönetimi (`permission_handler`)
  42. Bölüm 9 — Konu 42: Kamera, Konum, Sensörler
  43. Bölüm 9 — Konu 43: Push Notification (Firebase Cloud Messaging)
  44. Bölüm 9 — Konu 44: Android/iOS Build Sistemleri
  45. Bölüm 10 — Konu 45: Test Yazımı (Unit, Widget, Integration, Golden)
  46. Bölüm 10 — Konu 46: CI/CD
  47. Bölüm 10 — Konu 47: Rebuild Optimizasyonu (`const`, `key` Kullanımı)
  48. Bölüm 10 — Konu 48: DevTools Profiling
  49. Bölüm 10 — Konu 49: Lazy Loading, Pagination, Büyük Liste Performansı
  50. Bölüm 11 — Konu 50: Firebase Ekosistemi (Auth, Firestore, Storage, Functions)
  51. Bölüm 11 — Konu 51: Supabase Alternatifi
  52. Bölüm 11 — Konu 52: GraphQL (Opsiyonel)
  53. Bölüm 11 — Konu 53: Store Yayınlama Süreci (İmzalama, Listing, Versiyonlama)
  54. Bölüm 11 — Konu 54: App Size, Obfuscation, Flavor Yönetimi
  55. Bölüm 12 — Konu 55: Flutter Web / Desktop
  56. Bölüm 12 — Konu 56: Custom `RenderObject` Yazımı
  57. Bölüm 12 — Konu 57: Engine Mimarisi Derinlemesine (Impeller vs Skia)
  58. Bölüm 12 — Konu 58: Plugin Geliştirme, pub.dev'e Paket Yayınlama
  59. Bölüm 12 — Konu 59: Monorepo Mimarisi (Melos)
  60. Bölüm 12 — Konu 60: Erişilebilirlik (Accessibility) Derinlemesine
  61. Bölüm 12 — Konu 61: Yerelleştirme (Localization / i18n)
Dizinin sayfası →
İçindekiler 9 başlık
  1. BLoC Nedir? — Felsefi Farkı Anlama
  2. Cubit — BLoC'un Basitleştirilmiş Hali
  3. Widget İçinde Kullanım — BlocProvider ve BlocBuilder
  4. Cubit'in Metoduna Erişim — context.read
  5. Tam BLoC Pattern — Events ile
  6. Cubit mi, Tam BLoC mi?
  7. Üç Aracı Karşılaştıralım — Bölüm 6'nın Özeti
  8. 🎯 Bu Dersten Çıkarılması Gerekenler
  9. 📝 Ödevler

BLoC Nedir? — Felsefi Farkı Anlama

Şimdiye kadar gördüğümüz Provider ve Riverpod, "state'i tut ve değişince haber ver" felsefesiyle çalışıyordu. BLoC (Business Logic Component), biraz daha katı ve yapılandırılmış bir felsefeye sahiptir: "her state değişikliği, açıkça tanımlanmış bir 'olay' (event) sonucunda gerçekleşmelidir."

Bu, Dart Bölüm 13 Konu 61'de öğrendiğimiz event loop kavramına isim olarak benzese de, farklı bir şey — burada "event", kullanıcı eyleminin veya iş mantığı tetikleyicisinin açık bir temsilidir.

Cubit — BLoC'un Basitleştirilmiş Hali

BLoC ekosisteminde, önce daha basit olan Cubit'i öğrenmek mantıklıdır — Cubit, tam BLoC pattern'inin event katmanı olmayan bir versiyonudur.

bash
flutter pub add flutter_bloc
dart
import 'package:flutter_bloc/flutter_bloc.dart';

class SepetCubit extends Cubit<int> { // Dart Bölüm 9'u hatırla - generic!
  SepetCubit() : super(0); // başlangıç state'i: 0

  void ekle() {
    emit(state + 1); // "yeni bir state yayınla" — Riverpod'daki 'state =' ile BENZER
  }

  void azalt() {
    if (state > 0) emit(state - 1);
  }
}

Cubit<int> — Bölüm 6 Konu 25'te öğrendiğimiz Riverpod'un Notifier<int>'ine kavramsal olarak çok benzer — ikisi de generic (Dart Bölüm 9), ikisi de bir state kavramına sahip. emit(...), Riverpod'daki state = ... atamasının biraz daha açık (explicit) halidir — "yeni bir state değerini dünyaya yayınla" anlamına geliyor.

Widget İçinde Kullanım — BlocProvider ve BlocBuilder

dart
void main() {
  runApp(
    BlocProvider(
      create: (context) => SepetCubit(),
      child: MyApp(),
    ),
  );
}

BlocProvider, Bölüm 6 Konu 24'te öğrendiğimiz ChangeNotifierProvider'a yapısal olarak çok benziyor — create: ile (Dart Bölüm 3 Konu 11'deki builder pattern) bir Cubit/Bloc oluşturup widget ağacına "enjekte ediyor."

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

  @override
  Widget build(BuildContext context) {
    return BlocBuilder<SepetCubit, int>(
      builder: (context, sepetSayisi) {
        return Badge(
          label: Text('$sepetSayisi'),
          child: Icon(Icons.shopping_cart),
        );
      },
    );
  }
}

BlocBuilder<SepetCubit, int> — burada da Dart Bölüm 9'da öğrendiğimiz birden fazla generic tip parametresi kullanılıyor: SepetCubit (hangi Cubit'i dinleyeceği), int (state'in tipi). builder: fonksiyonu, Bölüm 5 Konu 18-19'da öğrendiğimiz FutureBuilder/StreamBuilder'ın builder pattern'ine çok benzer — context ve o anki state değeri parametre olarak veriliyor, state her emit() edildiğinde bu fonksiyon otomatik olarak yeniden çağrılıyor.

Cubit'in Metoduna Erişim — context.read

dart
ElevatedButton(
  onPressed: () {
    context.read<SepetCubit>().ekle(); // Provider'daki context.read ile AYNI sözdizimi!
  },
  child: Text('Sepete Ekle'),
)

flutter_bloc, Provider ile aynı context.read<T>()/context.watch<T>() sözdizimini kullanır (çünkü flutter_bloc, aslında arka planda provider paketini kullanır — bu, Dart Bölüm 12'de öğrendiğimiz paket bağımlılıklarının gerçek bir örneği). Bu, üç state management aracının (Provider, Riverpod, BLoC) birbirinden tamamen kopuk olmadığını, aksine ortak temellere (InheritedWidget) dayandığını gösteriyor.

Tam BLoC Pattern — Events ile

Cubit'ten bir adım öteye geçersek, tam BLoC pattern, state değişikliklerini event class'ları aracılığıyla tetikler — bu, Dart Bölüm 13 Konu 59'da öğrendiğimiz sealed class + pattern matching kavramının mükemmel bir kullanım alanıdır.

dart
sealed class SepetEvent {}
class UrunEklendi extends SepetEvent {
  final String urunAdi;
  UrunEklendi(this.urunAdi);
}
class SepetTemizlendi extends SepetEvent {}

class SepetBloc extends Bloc<SepetEvent, List<String>> {
  SepetBloc() : super([]) {
    on<UrunEklendi>((event, emit) {
      emit([...state, event.urunAdi]); // Dart Bölüm 4'ü hatırla — spread operatörü!
    });
    on<SepetTemizlendi>((event, emit) {
      emit([]);
    });
  }
}

Bloc<SepetEvent, List<String>> — iki generic parametre: gelen event tipi (SepetEvent, sealed class) ve state tipi (List<String>). on<UrunEklendi>((event, emit) { ... }), "bu tür bir event geldiğinde, şu işlemi yap" demenin yolu — Dart Bölüm 13 Konu 59'da öğrendiğimiz sealed class ile exhaustive kontrolün, bir event-driven mimaride nasıl doğal bir şekilde kullanılabileceğini gösteriyor.

emit([...state, event.urunAdi]) — Dart Bölüm 4 Konu 20'de öğrendiğimiz spread operatörü! Var olan state listesini kopyalayıp (immutability korunuyor — yeni bir liste oluşturuluyor, var olan liste değiştirilmiyor), yeni ürünü ekliyoruz.

Kullanım:

dart
context.read<SepetBloc>().add(UrunEklendi('Kalem'));

Cubit mi, Tam BLoC mi?

Cubit Tam BLoC
Karmaşıklık Düşük — direkt metod çağırma Yüksek — event class'ları gerekir
İzlenebilirlik (her state değişikliğinin "nedeni") Zayıf (hangi metod çağrıldı, kod okumadan belli olmaz) Güçlü (her event, açıkça bir "neden" temsil eder)
Test edilebilirlik İyi Çok iyi (event → state eşleşmesi net test edilir)
Ne zaman kullanılır Küçük-orta karmaşıklık, hızlı geliştirme Büyük takımlar, karmaşık iş mantığı, denetlenebilirlik önemliyse

Pratik tavsiye: flutter_bloc paketini kullanan projelerin çoğu, aslında Cubit ile başlar — tam BLoC pattern'in event-driven karmaşıklığı, genelde büyük, kurumsal projelerde (birden fazla geliştiricinin, "bu state neden değişti" sorusunu kod okumadan anlaması gerektiğinde) değerli hale gelir.

Üç Aracı Karşılaştıralım — Bölüm 6'nın Özeti

Provider Riverpod BLoC/Cubit
Temel mekanizma InheritedWidget (elle) InheritedWidget (context'siz) InheritedWidget (Provider üzerinden)
Context bağımlılığı Var Yok Var
Değişiklik bildirimi notifyListeners() state = ... emit(...)
Felsefe Basit, esnek Tip güvenli, test edilebilir Yapılandırılmış, event-driven (tam BLoC'ta)
Öğrenme eğrisi Düşük Orta Orta (Cubit) - Yüksek (tam BLoC)

🎯 Bu Dersten Çıkarılması Gerekenler

  • Cubit<T>, BLoC ekosisteminin basitleştirilmiş hali — emit(...) ile yeni state yayınlanır.
  • BlocProvider/BlocBuilder, Provider'ın ChangeNotifierProvider/context.watch'ına yapısal olarak benzer; flutter_bloc arka planda provider paketini kullanır.
  • Tam BLoC pattern, state değişikliklerini event class'ları (genelde sealed class ile) aracılığıyla tetikler — her değişikliğin "nedenini" açıkça izlenebilir kılar.
  • Cubit, hızlı geliştirme için; tam BLoC, büyük takımlarda denetlenebilirlik gerektiğinde tercih edilir.
  • Provider, Riverpod ve BLoC, hepsi temelde InheritedWidget mekanizmasına dayanır — farklı "arayüzler" sunan, ortak bir temele sahip araçlardır.

📝 Ödevler

  • [ ] Cubit<int> ile basit bir sayaç yaz, BlocProvider/BlocBuilder ile ekrana bağla.
  • [ ] Sealed class ile event'ler tanımlayan tam bir Bloc yaz (en az 2 farklı event tipiyle), on<EventTipi> ile her birini işle.
  • [ ] context.read<T>().add(Event()) ile bir event tetikle, state'in doğru güncellendiğini gözlemle.
  • [ ] Aynı basit sepet uygulamasını (önceki derslerdeki), bu sefer Cubit ile yeniden yaz.
  • [ ] Kendi cümlelerinle, Provider/Riverpod/Cubit arasındaki temel felsefe farkını (basit bildirim vs event-driven) özetleyen bir tablo/not hazırla.

Sıradaki konu: Bölüm 6 — Konu 27: GetX (Tartışmalı Ama Yaygın)