↑↓ seç · Enter aç · Esc kapat

Mutlu Tekin
Mutlu Tekin
← Yazılar

Bölüm 7 — Konu 30: `go_router` Paketi (Pratik ve Modern Çözüm)

3 dk okuma #flutter
Dizi · 30/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 12 başlık
  1. Paketi Ekleme
  2. Temel Kurulum — Bildirimsel Rota Tanımlama
  3. Dinamik Parametreler — :id Sözdizimi
  4. Ekranlar Arası Geçiş — context.go() ve context.push()
  5. Sorgu Parametreleri (Query Parameters)
  6. İç İçe Rotalar (Nested Routes) — Alt Navigasyon
  7. Named Routes — go_router'da Daha Güvenli Bir Versiyon
  8. Yönlendirme (Redirect) — Giriş Kontrolü Örneği
  9. go_router, Bölüm 7 Konu 29'daki Karmaşıklığı Nasıl Gizliyor?
  10. 🎯 Bu Dersten Çıkarılması Gerekenler
  11. 📝 Ödevler
  12. 🎮 Mini Uygulama — Deep-Linkable Ürün Kataloğu

Bir önceki derste Navigator 2.0'ın ham gücünü ve karmaşıklığını gördük. go_router, bu gücü çok daha basit bir API arkasına gizleyen, Flutter ekibinin resmi olarak önerdiği bir pakettir (flutter.dev paketleri arasında "Flutter Favorite" işaretlidir).

Paketi Ekleme

bash
flutter pub add go_router

Temel Kurulum — Bildirimsel Rota Tanımlama

dart
import 'package:go_router/go_router.dart';

final _router = GoRouter(
  routes: [
    GoRoute(
      path: '/',
      builder: (context, state) => AnaEkran(),
    ),
    GoRoute(
      path: '/urun/:id',
      builder: (context, state) {
        final id = state.pathParameters['id']!;
        return UrunDetayEkrani(urunId: id);
      },
    ),
  ],
);

void main() {
  runApp(MaterialApp.router(
    routerConfig: _router,
  ));
}

Dikkat et — bu ne kadar tanıdık! routes: [...], Dart Bölüm 4'te öğrendiğimiz List yapısı; her GoRoute, Bölüm 3 Konu 14'te öğrendiğimiz Named Routes'daki Map<String, WidgetBuilder> mantığına çok benzer, ama çok daha güçlü özelliklerle (dinamik parametreler, iç içe rotalar) genişletilmiş.

builder: (context, state) => ... — Bölüm 3 Konu 11'de öğrendiğimiz builder pattern'in bir başka örneği. state, o anki rota hakkında bilgi taşır (URL parametreleri, sorgu parametreleri gibi).

Dinamik Parametreler — :id Sözdizimi

dart
GoRoute(
  path: '/urun/:id',
  builder: (context, state) {
    final id = state.pathParameters['id']!;
    return UrunDetayEkrani(urunId: id);
  },
)

:id, URL'nin değişken bir parçası olduğunu belirtir — /urun/123 veya /urun/abc gibi, herhangi bir değer bu yolla eşleşir. state.pathParameters['id'], Dart Bölüm 4'te öğrendiğimiz Map<String, String> erişimidir (Bölüm 3 Konu 14'te arguments'ı as String ile cast etmek zorunda kaldığımızı hatırlarsan — burada pathParameters, zaten String tipinde geliyor, bu daha temiz bir tip güvenliği).

Ekranlar Arası Geçiş — context.go() ve context.push()

dart
ElevatedButton(
  onPressed: () {
    context.go('/urun/123'); // mevcut yığını DEĞİŞTİRİR
  },
  child: Text('Ürüne Git'),
)
dart
ElevatedButton(
  onPressed: () {
    context.push('/urun/123'); // yığına EKLER (Navigator.push'a benzer)
  },
  child: Text('Ürüne Git'),
)

go() ile push() arasındaki fark: go(), Bölüm 3 Konu 14'te öğrendiğimiz stack (yığın) kavramını hatırlarsan, mevcut yığını tamamen yeni bir rotayla değiştirir (web'de "adres çubuğuna URL yazmak" gibi düşün). push(), geleneksel Navigator 1.0'ın push'una daha yakın davranır — yığına ekler, geri tuşuyla önceki ekrana dönülebilir.

Sorgu Parametreleri (Query Parameters)

dart
context.go('/arama?q=laptop&kategori=elektronik');
dart
GoRoute(
  path: '/arama',
  builder: (context, state) {
    final sorgu = state.uri.queryParameters['q'];
    final kategori = state.uri.queryParameters['kategori'];
    return AramaSonuclari(sorgu: sorgu, kategori: kategori);
  },
)

state.uri.queryParameters, yine Map<String, String> — web tarayıcılarında gördüğün ?q=laptop&kategori=elektronik tarzı URL'lerin doğal Flutter karşılığı.

İç İçe Rotalar (Nested Routes) — Alt Navigasyon

dart
GoRoute(
  path: '/urunler',
  builder: (context, state) => UrunlerEkrani(),
  routes: [ // İÇ İÇE rotalar
    GoRoute(
      path: ':id', // tam yolu: /urunler/:id
      builder: (context, state) {
        final id = state.pathParameters['id']!;
        return UrunDetayEkrani(urunId: id);
      },
    ),
  ],
)

Bu, Dart Bölüm 4'te öğrendiğimiz iç içe koleksiyon yapılarına benzer bir hiyerarşi — routes: içinde başka routes: tanımlayarak, URL yapısını ağaç şeklinde organize edebilirsin (/urunler/:id, /urunler/:id/yorumlar gibi).

Named Routes — go_router'da Daha Güvenli Bir Versiyon

dart
GoRoute(
  path: '/urun/:id',
  name: 'urun-detay', // bir İSİM veriyoruz
  builder: (context, state) => UrunDetayEkrani(urunId: state.pathParameters['id']!),
)
dart
context.goNamed('urun-detay', pathParameters: {'id': '123'});

Bu, Bölüm 3 Konu 14'te öğrendiğimiz Named Routes'un go_router versiyonudur — URL string'ini elle yazmak yerine (yazım hatası riski), isimle ve tip güvenli parametrelerle rotaya gidiyorsun.

Yönlendirme (Redirect) — Giriş Kontrolü Örneği

dart
final _router = GoRouter(
  redirect: (context, state) {
    final girisYapildiMi = false; // gerçek uygulamada bir state'ten gelir (Bölüm 6'yı hatırla)
    final girisSayfasindaMi = state.matchedLocation == '/giris';

    if (!girisYapildiMi && !girisSayfasindaMi) {
      return '/giris'; // giriş yapılmamışsa, giriş ekranına yönlendir
    }
    return null; // null = yönlendirme yok, olduğu gibi devam
  },
  routes: [...],
);

redirect, Dart Bölüm 5'te öğrendiğimiz anonim fonksiyondur — her navigasyon denemesinde çalışır ve null (yönlendirme yok) veya bir String (yeni hedef yol) döndürür. Bu, gerçek uygulamalarda "giriş yapılmadan belirli ekranlara erişilemez" gibi kuralları merkezi bir yerde uygulamanın standart yoludur.

go_router, Bölüm 7 Konu 29'daki Karmaşıklığı Nasıl Gizliyor?

go_router, arka planda tam olarak bir önceki derste öğrendiğimiz RouteInformationParser ve RouterDelegate'i kendi içinde implemente eder — sen bunları görmüyorsun bile, sadece GoRoute listesi tanımlıyorsun. Bu, Bölüm 5 Konu 20'de dio'nun http'nin üzerine, veya Bölüm 6 Konu 24'te Provider'ın InheritedWidget'ın üzerine inşa edilmesiyle aynı mühendislik deseni — karmaşık, güçlü bir temeli, basit bir arayüz arkasında sunmak.


🎯 Bu Dersten Çıkarılması Gerekenler

  • go_router, Navigator 2.0'ın gücünü, GoRoute listesi ile bildirimsel ve basit bir API arkasında sunar.
  • :parametre sözdizimi, dinamik URL parçalarını yakalar; state.pathParameters/state.uri.queryParameters, tip güvenli erişim sağlar.
  • context.go(), yığını değiştirir; context.push(), yığına ekler (Navigator 1.0'a benzer).
  • İç içe routes:, URL yapısını ağaç şeklinde organize etmeyi sağlar.
  • redirect, merkezi navigasyon kurallarını (örn. giriş kontrolü) uygulamanın standart yoludur.

📝 Ödevler

  • [ ] go_router ile en az 3 route'lu (ana sayfa, liste, detay) bir navigasyon yapısı kur.
  • [ ] Dinamik bir parametre (:id) içeren bir route yaz, context.go() ile farklı ID'lerle test et.
  • [ ] Bir arama ekranı için sorgu parametreleri (?q=...) kullan, state.uri.queryParameters ile oku.
  • [ ] İç içe route'lar (nested routes) kullanarak, en az 2 seviyeli bir URL yapısı (/urunler/:id) kur.
  • [ ] redirect kullanarak basit bir "giriş yapılmadan erişilemez" kontrolü ekle (sabit bir bool değişkenle test edebilirsin).

🎮 Mini Uygulama — Deep-Linkable Ürün Kataloğu

Bölüm 7'de öğrendiğin navigasyon bilgisini pekiştiren bir mini proje:

Gereksinimler:

  • go_router ile en az 4 route: ana sayfa, ürün listesi, ürün detayı (:id ile), ve bir "hakkında" sayfası.
  • Ürün listesinden bir ürüne tıklandığında, context.go() ile detay sayfasına geç.
  • Detay sayfasında bir "geri" butonu ile ana listeye dön.
  • Bir arama kutusu ekle, context.go('/urunler?q=...') ile sorgu parametresiyle listeyi filtrele (gerçek filtreleme mantığı basit olabilir — örn. sadece parametreyi ekranda gösterebilirsin).
  • Bonus: redirect ile, sahte bir "bakım modu" bayrağı true olduğunda tüm rotaları bir "bakımdayız" ekranına yönlendir.

Sıradaki konu: Bölüm 7 — Konu 31: Deep Linking