Flutter'da State Management 2026: Riverpod vs Bloc vs GetX

Flutter state management cozumlerinin 2026 yilinda pratik karsilastirmasi. Riverpod 3.0, Bloc 9.0 ve GetX gercek kod ornekleri, performans karsilastirmalari ve gecis stratejileriyle degerlendirildi.

Riverpod, Bloc ve GetX mimari desenlerini gosteren Flutter state management karsilastirma diyagrami

Flutter'da state management, bir uygulamanin widget'lar arasindaki veri akisini nasil yonettigini tanimlar. 2026 yilinda ekosisteme uc cozum hakim durumda: derleme zamani guvenligi sunan Riverpod 3.0, kurumsal sinif olay izleme kapasitesine sahip Bloc 9.0 ve azalan ancak hala var olan kullanim alani bulunan GetX. Dogru cozumun secimi test edilebilirlik, olceklenebilirlik ve uzun vadeli bakim maliyetlerini dogrudan etkiler.

Quick Decision Framework

Riverpod 3.0, derleme zamani guvenligi ve minimum boilerplate ile cogu proje icin ideal secimdir. Bloc 9.0, olay tabanli denetim izleri gerektiren regulasyona tabi sektorlerde standart olmaya devam etmektedir. GetX, yalnizca gecis butcesi bulunmayan mevcut kod tabanlarinin bakimi icin dusunulmelidir.

Riverpod 3.0: Derleme Zamani Guvenligi ve Otomatik Yeniden Deneme

Riverpod 3.0, Flutter uygulamalarinin state tanimlama ve tuketme bicimine koklü bir degisiklik getirdi. Anotasyon tabanli kod uretimi, bagimlilk hatalarini calisma zamani yerine derleme zamaninda yakalar ve daha once manuel test gerektiren tum bir hata sinifini ortadan kaldirir.

Basarisiz olan provider'lar icin otomatik yeniden deneme mekanizmasi, gecici ag hatalarini manuel mudahale olmadan yonetir. Bir provider hesaplamasi basarisiz oldugunda, Riverpod yapilandrilabilir gecikmeyle otomatik olarak yeniden dener ve hata kurtarma boilerplate kodunu azaltir.

counter_provider.dartdart
import 'package:riverpod_annotation/riverpod_annotation.dart';

part 'counter_provider.g.dart';

// Code generation ensures compile-time safety

class Counter extends _$Counter {
  
  int build() => 0; // Initial state

  void increment() => state = state + 1;
  void decrement() => state = state - 1;
  void reset() => state = 0;
}

@riverpod anotasyonu tum provider boilerplate'ini olusturur. Tip uyumsuzluklari, eksik override'lar ve dongusel bagimliliklar derleme sirasinda ortaya cikar.

user_repository_provider.dartdart
import 'package:riverpod_annotation/riverpod_annotation.dart';

part 'user_repository_provider.g.dart';


Future<User> currentUser(Ref ref) async {
  final authService = ref.watch(authServiceProvider);
  final userId = authService.currentUserId;

  // Auto-retry on network failure (Riverpod 3.0)
  final response = await ref.watch(
    httpClientProvider,
  ).get('/api/users/$userId');

  return User.fromJson(response.data);
}

Riverpod 3.0, bir widget ekrandan ayrildiginda provider dinleyicilerini otomatik olarak durdurur; bu, gereksiz hesaplamalari azaltir ve mobil cihazlarda pil omrunu iyilestirir.

Bloc 9.0: Kurumsal Uygulamalar icin Olay Tabanli Mimari

Bloc 9.0, olaylar, state'ler ve is mantigi arasinda katı bir ayrim uygular. Her state degisikligi belirli bir olaya eslestirilir ve regulasyona tabi sektorlerin ihtiyac duydugu denetim izini olusturur. Surum 9.0'daki mount guvenlik kontrolleri, geri cagirmalarin dispose edilmis widget'lar uzerinde calismasini onler.

authentication_event.dartdart
sealed class AuthenticationEvent {}

final class LoginRequested extends AuthenticationEvent {
  final String email;
  final String password;
  LoginRequested({required this.email, required this.password});
}

final class LogoutRequested extends AuthenticationEvent {}

final class SessionRestored extends AuthenticationEvent {
  final String token;
  SessionRestored({required this.token});
}

Dart 3 sealed siniflar, olaylar uzerinde kapsamli desen eslestirme garantisi saglar. Derleyici, her olay turune bir handler atanmasini zorunlu kilar.

authentication_bloc.dartdart
import 'package:flutter_bloc/flutter_bloc.dart';

class AuthenticationBloc
    extends Bloc<AuthenticationEvent, AuthenticationState> {
  final AuthRepository _authRepo;
  final TokenStorage _tokenStorage;

  AuthenticationBloc({
    required AuthRepository authRepo,
    required TokenStorage tokenStorage,
  })  : _authRepo = authRepo,
        _tokenStorage = tokenStorage,
        super(AuthenticationInitial()) {
    on<LoginRequested>(_onLoginRequested);
    on<LogoutRequested>(_onLogoutRequested);
    on<SessionRestored>(_onSessionRestored);
  }

  Future<void> _onLoginRequested(
    LoginRequested event,
    Emitter<AuthenticationState> emit,
  ) async {
    emit(AuthenticationLoading());
    try {
      final token = await _authRepo.login(
        email: event.email,
        password: event.password,
      );
      await _tokenStorage.save(token);
      emit(AuthenticationSuccess(token: token));
    } catch (e) {
      emit(AuthenticationFailure(message: e.toString()));
    }
  }

  Future<void> _onLogoutRequested(
    LogoutRequested event,
    Emitter<AuthenticationState> emit,
  ) async {
    await _tokenStorage.clear();
    emit(AuthenticationInitial());
  }

  Future<void> _onSessionRestored(
    SessionRestored event,
    Emitter<AuthenticationState> emit,
  ) async {
    emit(AuthenticationSuccess(token: event.token));
  }
}

Her olay handler'i acik bir state gecisi uretir. Loglama middleware'i, hata ayiklama veya uyumluluk amaciyla her olayi kaydedebilir. Bloc 9.0'daki EmittableStateStreamableSource arayuzu, hafif mock uygulamalari olusturmayi mumkun kilarak test surecini basitlestirir.

Bloc Olay Transformerlari: Yuksek Frekanslı Giris Yonetimi

Bloc, yaygin esaomanlilik problemlerini cozen yerlesik olay transformerlari saglar. Yazarken arama, hizli buton tiklamalari ve gercek zamanli veri akislari, bildirimsel olay islemeden faydalanir.

search_bloc.dartdart
import 'package:bloc_concurrency/bloc_concurrency.dart';
import 'package:flutter_bloc/flutter_bloc.dart';

class SearchBloc extends Bloc<SearchEvent, SearchState> {
  final SearchRepository _repository;

  SearchBloc({required SearchRepository repository})
      : _repository = repository,
        super(SearchInitial()) {
    // restartable() cancels previous search on new input
    on<SearchQueryChanged>(
      _onQueryChanged,
      transformer: restartable(),
    );
    // droppable() ignores events while processing
    on<SearchResultSelected>(
      _onResultSelected,
      transformer: droppable(),
    );
  }

  Future<void> _onQueryChanged(
    SearchQueryChanged event,
    Emitter<SearchState> emit,
  ) async {
    if (event.query.length < 3) {
      emit(SearchInitial());
      return;
    }
    emit(SearchLoading());
    final results = await _repository.search(event.query);
    emit(SearchLoaded(results: results));
  }

  Future<void> _onResultSelected(
    SearchResultSelected event,
    Emitter<SearchState> emit,
  ) async {
    emit(SearchNavigating(result: event.result));
  }
}

restartable() transformeri, yeni bir giris geldiginde devam eden aramayi iptal ederek eski sonuclarin yeni sonuclarin uzerine yazilmasini onler. droppable() transformeri, bir navigasyon islemi devam ederken tekrarlanan tiklamalari yok sayar.

Flutter mülakatlarında başarılı olmaya hazır mısın?

İnteraktif simülatörler, flashcards ve teknik testlerle pratik yap.

GetX: Teknik Borc ve Gecis Gerçekleri

GetX, hizli prototipleme ve minimum boilerplate sayesinde popülerlik kazandi. 2026 yilinda kutuphane bir bakim kriziyle karsi karsiya: duzenisiz guncellemeler, tek bakimci darboğazi ve Flutter SDK'nin son surümleriyle artan uyumsuzluklar. GetX kullanan uretim uygulamalari, controller yasam dongusu sorunlari ve örtük global singleton'lardan kaynaklanan bellek sızıntılariyla karsilasir.

counter_controller.dart (GetX pattern)dart
import 'package:get/get.dart';

// Global singleton - difficult to test and scope
class CounterController extends GetxController {
  final count = 0.obs; // Reactive observable

  void increment() => count.value++;
  void decrement() => count.value--;

  // Lifecycle hooks - disposal timing is unpredictable
  
  void onClose() {
    // Cleanup may not execute reliably
    super.onClose();
  }
}

// Usage in widget
class CounterPage extends StatelessWidget {
  
  Widget build(BuildContext context) {
    // Get.put creates a global singleton
    final controller = Get.put(CounterController());
    return Obx(() => Text('${controller.count}'));
  }
}

Get.put() cagrisi, controller'lari global singleton olarak kaydeder. Karmasik navigasyon akislarinda controller'lar hedeflenen kapsamin otesinde kalici olur ve bellek tuketir. .obs reaktif degiskenleri, Flutter'in standart state bildirim sistemini atlatir ve diger paketlerle entegrasyonu guvenilmez kilar.

GetX'ten Riverpod'a Gecis: Adim Adim

GetX kod tabanlarini yoneten ekipler, Riverpod'a gecisi kademeli olarak gerceklestirebilir. Her iki kutuphane ayni projede bir arada var olabilir ve tam bir yeniden yazim gerektirmeden ekran ekran donusum yapilmasina olanak tanir.

dart
// Step 1: Replace GetX controller with Riverpod notifier
// Before (GetX)
class ProductController extends GetxController {
  final products = <Product>[].obs;
  final isLoading = false.obs;

  Future<void> loadProducts() async {
    isLoading.value = true;
    products.value = await ProductApi.fetchAll();
    isLoading.value = false;
  }
}

// After (Riverpod 3.0)

class ProductList extends _$ProductList {
  
  Future<List<Product>> build() async {
    // Auto-retry on failure, auto-pause when off-screen
    return ProductApi.fetchAll();
  }

  Future<void> refresh() async {
    ref.invalidateSelf();
  }
}
dart
// Step 2: Replace widget bindings
// Before (GetX)
class ProductPage extends StatelessWidget {
  
  Widget build(BuildContext context) {
    final ctrl = Get.put(ProductController());
    return Obx(() {
      if (ctrl.isLoading.value) return CircularProgressIndicator();
      return ListView.builder(
        itemCount: ctrl.products.length,
        itemBuilder: (_, i) => ProductTile(ctrl.products[i]),
      );
    });
  }
}

// After (Riverpod 3.0)
class ProductPage extends ConsumerWidget {
  
  Widget build(BuildContext context, WidgetRef ref) {
    final productsAsync = ref.watch(productListProvider);
    return productsAsync.when(
      loading: () => const CircularProgressIndicator(),
      error: (err, stack) => ErrorDisplay(error: err),
      data: (products) => ListView.builder(
        itemCount: products.length,
        itemBuilder: (_, i) => ProductTile(products[i]),
      ),
    );
  }
}

Riverpod surumu, yukleme, hata ve veri state'lerini AsyncValue.when() araciligiyla acikca yonetir. Global singleton yok, manuel yasam dongusu yonetimi yok ve widget unmount edildiginde otomatik temizleme saglanir.

Performans Karsilastirmasi: Yeniden Olusturma Verimliligi

Yeniden olusturma verimliligi kare hizlarini dogrudan etkiler. Her cozum widget yeniden olusturmayi farkli sekilde ele alir ve fark, yuzlerce oge iceren listelerde olculebilir hale gelir.

| Metric | Riverpod 3.0 | Bloc 9.0 | GetX | |--------|-------------|----------|------| | Selective rebuild | select() filter | BlocSelector | .obs per field | | Compile-time safety | Full (code gen) | Partial (sealed classes) | None | | Auto-dispose | Built-in | Manual via close() | Unreliable | | Pause when off-screen | Automatic (3.0) | Manual | Not supported | | Event traceability | Provider observer | Full event log | None | | Testing isolation | ProviderContainer.test() | EmittableStateStreamableSource | Requires Get.testMode | | Bundle size impact | ~45KB | ~38KB | ~120KB (includes routing, DI, HTTP) |

Riverpod'un select() metodu ve Bloc'un BlocSelector'u, yalnizca degisen veriye bagli widget alt agacini guncelleyerek cerrahi hassasiyetinde yeniden olusturma saglar. GetX'in .obs degiskenleri alan bazinda benzer granularite elde eder, ancak bagimlilk grafiginin derleme zamani dogrulamasini sunmaz.

GetX Bundle Size

GetX; routing, bagimlilk enjeksiyonu, HTTP istemcisi ve state management'i tek bir pakette bir araya getirir. Yalnizca state management kullanan uygulamalar bile 120 KB'lik kutuphanenin tamamini iceri aktarir. Riverpod ve Bloc, tek bir isi iyi yapan odakli paketlerdir.

Cozumler Arasi Test Stratejileri

Test edilebilirlik, buyuyen bir ekiple hangi cozumun olceklendirildigi konusunda genellikle belirleyici faktordur. Her kutuphane test konusuna farkli yaklasir.

dart
// Riverpod test - isolated container
import 'package:flutter_test/flutter_test.dart';
import 'package:riverpod/riverpod.dart';

void main() {
  test('Counter increments', () {
    final container = ProviderContainer.test();
    // Override dependencies for isolation
    final counter = container.read(counterProvider.notifier);

    expect(container.read(counterProvider), 0);
    counter.increment();
    expect(container.read(counterProvider), 1);
  });
}
dart
// Bloc test - event-driven verification
import 'package:bloc_test/bloc_test.dart';
import 'package:flutter_test/flutter_test.dart';

void main() {
  blocTest<AuthenticationBloc, AuthenticationState>(
    'emits [loading, success] on valid login',
    build: () => AuthenticationBloc(
      authRepo: MockAuthRepo(),
      tokenStorage: MockTokenStorage(),
    ),
    act: (bloc) => bloc.add(
      LoginRequested(email: 'dev@test.com', password: 'secure123'),
    ),
    expect: () => [
      isA<AuthenticationLoading>(),
      isA<AuthenticationSuccess>(),
    ],
  );
}

Riverpod'un ProviderContainer.test() metodu her test icin izole bir bagimlilk grafi olusturur. Bloc'un blocTest yardimcisi, olay tabanli mimariyle uyumlu olarak kesin state gecis dizilerini dogrular. GetX testi, Get.testMode = true ayarlanmasini ve controller yasam dongusunun manuel yonetimini gerektirir; bu durum CI ortamlarinda siklikla kararsiz testlere yol acar.

Interview Preparation

Flutter state management, mobil gelistirici mulakatlari icinde en sik sorulan konular arasindadir. Riverpod, Bloc ve GetX arasindaki odunlesimleri anlamak, mimari olgunlugu gosterir. Her cozumun ne zaman uygun oldugunu ve ne zaman olmadigini aciklama pratiği yapilmalidir.

Karar Matrisi: Dogru Cozumu Secmek

Proje kisitlamalari en iyi uyumu belirler. Ekip buyuklugu, regulasyon gereksinimleri ve mevcut kod tabani karara etki eden faktorlerdir.

Riverpod 3.0, ekibin derleme zamani guvenligine deger verdigi, projenin otomatik hata kurtarma ile asenkron veri cekme gerektirdigi veya kod tabaninin sifirdan olusturuldugu durumlarda uygundur. Ogrenme egrisi olculu duzeydedir: Provider'a asina olan gelistiriciler dogal bir sekilde gecis yapar.

Bloc 9.0, projenin regulasyona tabi bir sektorde faaliyet gosterdigi (fintech, saglik), ekibin denetim amaciyla tam olay izlenebilirligi gerektirdigi veya uygulamanin odeme isleme gibi karmasik esaomanli is akislarini yonettigi durumlarda uygundur. Boilerplate maliyeti, olcekte bakım kolayligiyla kendini amorti eder.

GetX, yalnizca gecis maliyetinin mevcut butceyi astigi mevcut GetX kod tabanlarinin bakiminda uygundur. 2026 yilinda GetX ile yeni projelere baslamak, ilk gunden teknik borc olusturur. Resmi Flutter dokumantasyonu GetX'i onerilen cozumler arasinda listememektedir.

Flutter state management desenleri uzerine derinlesmek isteyenler icin Flutter state management temelleri modulu, mulakatlarda test edilen temel kavramlari kapsar. Provider pattern modulu, her uc cozumde de gecerli olan bagimlilk enjeksiyonu stratejilerini inceler.

Pratik yapmaya başla!

Mülakat simülatörleri ve teknik testlerle bilgini test et.

Sonuc

  • Riverpod 3.0, kod uretimi araciligiyla derleme zamani guvenligi, basarisiz provider'lar icin otomatik yeniden deneme ve mobil cihazlarda pil tuketimini azaltan duraklatma/devam ettirme destegi saglar
  • Bloc 9.0, tam denetim kapasitesiyle olay tabanli state gecislerini zorunlu kilar ve regulasyona tabi sektorlerde kurumsal uygulamalar icin standart haline gelir
  • GetX, 2026 yilinda sporadik guncellemeler ve artan SDK uyumsuzluklariyla bir bakim kriziyle karsi karsiyadir; mevcut GetX projeleri Riverpod'a kademeli gecis planlamalidir
  • GetX'ten Riverpod'a gecis, her iki kutuphane ayni projede bir arada var olabildiginden, tam bir yeniden yazim gerektirmeden ekran ekran ilerler
  • Test izolasyonu onemli olcude farklilik gosterir: Riverpod ProviderContainer.test() kullanir, Bloc olay dizisi dogrulamasiyla blocTest kullanir ve GetX kirilgan global test modu yapilandirmasi gerektirir
  • Paket boyutu mobil cihazlarda onemlidir: Riverpod (~45 KB) ve Bloc (~38 KB) odakli paketler sunarken, GetX (~120 KB) kullanilmayan ozellikleri bir arada paketler

Pratik yapmaya başla!

Mülakat simülatörleri ve teknik testlerle bilgini test et.

Etiketler

#flutter
#state-management
#riverpod
#bloc
#getx
#dart

Paylaş

İlgili makaleler