Herkese merhaba. Bugün sizlere çoğumuz için karmaşık gelen StateManagement konusu ile geldim. Hemen başlayalım.
Flutter projeniz ilk başta minik bir “merhaba dünya” uygulaması gibi masum görünebilir. Ama işler büyüyüp ekranlar, API çağrıları, kullanıcı etkileşimleri ve veri yönetimi devreye girdiğinde, state management konusu bir anda korku filmine dönüşebilir.
Yanlış state yönetimi:
- Uygulamanızı yavaşlatır.
- Kodun okunabilirliğini bitirir.
- Takım içi çalışmayı zorlaştırır.
- Ve en kötüsü, gelecekte hata ayıklamayı imkânsız hale getirir.
Bu yazıda, Flutter’da state yönetimi yaparken en sık karşılaşılan 10 hatayıgerçek kod örnekleri ve çözüm yollarıyla inceleyeceğiz.
Ayrıca, bu hataları nasıl önceden fark edebileceğinizi ve daha performanslı, sürdürülebilir kod yazabileceğinizi konuşacağız.
1. Tüm State’i Tek Yere Toplamak
Hata: Tek bir Provider, Bloc veya State sınıfı içine tüm uygulamanın state’ini koymak.
class AppState with ChangeNotifier {
String userName = '';
int cartItemCount = 0;
bool isDarkMode = false;
List<String> notifications = [];
void updateUserName(String name) {
userName = name;
notifyListeners();
}
void addNotification(String message) {
notifications.add(message);
notifyListeners();
}
}
Bu yapı küçük projede masum görünür. Ancak proje büyüdükçe:
- Gereksiz rebuild’ler olur (tek alan değişse bile tüm dinleyiciler tetiklenir).
- Kod karmaşıklaşır.
- Test etmek zorlaşır.
Çözüm:
Modüler state yönetimi → Her feature için ayrı state sınıfları veya Bloc’lar.
class UserState with ChangeNotifier {
String userName = '';
void updateUserName(String name) {
userName = name;
notifyListeners();
}
}
class CartState with ChangeNotifier {
int itemCount = 0;
void addItem() {
itemCount++;
notifyListeners();
}
}
2. Gereksiz Rebuild’ler
Hata: Consumer
veya BlocBuilder
ile tüm ekranı sarmak.
Consumer<CartState>(
builder: (context, cart, child) {
return Scaffold(
appBar: AppBar(title: Text('Cart (${cart.itemCount})')),
body: ProductList(),
);
},
);
itemCount
değiştiğinde tüm ekran yeniden çizilir.
Çözüm:
Sadece gerekli kısmı rebuild etmek için Selector
veya küçük widget’lar kullanın.
AppBar(
title: Selector<CartState, int>(
selector: (context, cart) => cart.itemCount,
builder: (context, count, child) => Text('Cart ($count)'),
),
)
3. Local ve Global State’i Karıştırmak
Hata: UI’ye özgü verileri global state’te tutmak.
Örnek: Modal açık/kapalı durumu globalde tutuluyor.
class AppState with ChangeNotifier {
bool isModalOpen = false;
}
Çözüm:
Ekrana özel state’leri StatefulWidget
içinde veya local provider’da tutun.
class MyScreen extends StatefulWidget {
@override
State<MyScreen> createState() => _MyScreenState();
}
class _MyScreenState extends State<MyScreen> {
bool isModalOpen = false;
}
4. Business Logic ile UI’nin Karışması
Hata: API çağrıları veya veri işleme kodunun doğrudan widget içinde olması.
ElevatedButton(
onPressed: () async {
final data = await fetchData();
setState(() {
result = data;
});
},
child: Text("Load"),
)
Çözüm:
İş mantığını state management katmanına taşıyın.
class DataState with ChangeNotifier {
String result = '';
Future<void> loadData() async {
result = await fetchData();
notifyListeners();
}
}
5. Immutable Olmayan State Kullanımı
Hata: State objesini doğrudan değiştirmek.
state.user.name = 'John'; // False
Çözüm:
State’i immutable tutmak, copyWith
kullanmak.
class User {
final String name;
User({required this.name});
User copyWith({String? name}) {
return User(name: name ?? this.name);
}
}
6. dispose() ve Memory Management İhmali
Hata: Stream, Controller veya Timer’ları dispose etmemek.
class MyNotifier with ChangeNotifier {
final controller = StreamController();
}
Çözüm:dispose()
metodunu eklemek.
@override
void dispose() {
controller.close();
super.dispose();
}
7. Provider’da notifyListeners()’ın Fazla Kullanımı
Hata: Tek bir değişiklik için tüm dinleyicileri tetiklemek.
void updateCart() {
itemCount++;
notifyListeners();
}
Çözüm:
Veriyi parçalara ayırmak veya context.select()
ile hedef rebuild yapmak.
8. Bloc’ta Tek Event ile Her Şeyi Yönetmek
Hata: Tüm işlemleri tek event’te toplamak.
class AppEvent {}
Çözüm:
Her işlem için ayrı event tanımlayın.
class LoadUser extends AppEvent {}
class UpdateCart extends AppEvent {}
9. GetX’te Gereksiz Reactive Variable Tanımlamak
Hata: Değişmeyecek verileri bile .obs
yapmak.
final appName = 'MyApp'.obs; // Not useful
Çözüm:
Sadece değişen ve UI’yi etkileyen değerleri reactive yapın.
10. Yanlış Kütüphane Seçimi
Hata: Proje ihtiyacını analiz etmeden popüler olduğu için kütüphane seçmek.
Çözüm:
- Küçük projeler → Provider / Riverpod
- Orta projeler → Riverpod / Bloc
- Büyük ekip projeleri → Bloc / Clean Architecture
Sonuç ve Öneriler
- State yönetimini proje başında doğru planlayın.
- Modüler yaklaşım kullanın.
- Gereksiz rebuild’leri azaltın.
- Immutable veri yapıları tercih edin.
- Test edilebilirliği göz ardı etmeyin.
Buraya kadar okuduğun için teşekkür ederim.
Bu yazıyı beğendiysen alkış butonuna tıklamayı unutma. Diğer içeriklerimden haberdar olmak için abone olabilirsin.
Teşekkür ederim.
Selin.
Hiç yorum yok:
Yorum Gönder