StatefulWidget, değişebilir duruma sahip bir Flutter widget'ıdır ve kullanıcı eylemlerine, asenkron olaylara ve veri akışlarına UI'nin tepki vermesini sağlar. Resmi Flutter belgelerine (Flutter.dev, 2026) göre StatefulWidget, uygulamanın tüm etkileşimli öğeleri için kullanılır: giriş formları, animasyonlar, onay kutuları, anahtarlar ve ağdan veri yükleyen ekranlar. StatelessWidget'ın aksine, tüm yaşam döngüsü boyunca kalıcı olan ayrı bir State nesnesi oluşturur ve widget'ın kendisini yeniden oluşturmadan yeniden oluşturulabilir.
Önemli Noktalar
StatefulWidget, kullanıcı eylemlerine, sistem olaylarına veya asenkron işlemlere yanıt olarak durumunu değiştirebilen bir Flutter sınıfıdır. StatelessWidget'ın aksine, StatefulWidget doğrudan işlenmez — işlemeyi üstlenen bir State nesnesi oluşturur. Widget ve State olmak üzere iki sınıfa ayrılma, Flutter'ın widget'ın kendisini yeniden oluşturmadan UI'yi yeniden oluşturmasını sağlar ve sık güncellemeler sırasında önemli bir performans avantajı sağlar.
StatefulWidget'ın mimarisi “değişebilir ve değişmez ayrımı” modelini izler: widget'ın kendisi değişmez kalırken (StatelessWidget gibi), tüm değişebilir durum ayrı bir State nesnesinde depolanır. Bu, Flutter'ın widget'ları tür ve Key'e göre karşılaştırarak yeniden kullanmasını sağlar ve yeniden oluşturmalar arasında gerçek durumu korur.
Google'a (Flutter Architectural Overview, 2026) göre StatefulWidget, widget'ın ömrü boyunca durumun birden fazla kez değiştiği senaryolar için idealdir: metin alanları, animasyonlar, zamanlayıcılar, veri akışları, asenkron yüklemeler. Tek seferlik başlatma için StatelessWidget yeterlidir.
StatefulWidget, widget'ın harici olaylara yanıt vermesi gerektiğinde zorunludur: düğme tıklamaları, HTTP isteklerinin tamamlanması, veritabanı güncellemeleri, WebSocket abonelikleri. Ayrıca animasyonlu widget'lar, denetleyicili metin alanları ve odağı yöneten bileşenler için de gereklidir. Bir widget yalnızca veri görüntülüyorsa ve olay oluşturmuyorsa StatelessWidget kullanın.
StatefulWidget iki sınıftan oluşur: StatefulWidget'ın kendisi (hafif, değişmez) ve State (ağır, değişebilir). Çerçeve, ağaca eklendiğinde bir kez çağrılan createState() yöntemi aracılığıyla State oluşturur. State, widget özelliği aracılığıyla widget'a bir referans alır ve yaşam döngüsünün herhangi bir noktasında alanlarına erişebilir.
Yaşam döngüsü altı ana aşamadan oluşur ve her biri belirli görevleri gerçekleştirmek için geçersiz kılınabilir bir yöntem sağlar. Bu aşamaları anlamak, uygun kaynak yönetimi ve bellek sızıntılarını önlemek için kritiktir.
createState, StatefulWidget ağaca eklendiğinde çağrılan ilk yaşam döngüsü yöntemidir. Bu widget ile ilişkili yeni bir State örneği döndürmelidir. Bu yöntem, öğenin tüm yaşamı boyunca tam olarak bir kez çağrılır. Burada ağır işlemler yapmamak önemlidir — createState mümkün olduğunca hafif olmalıdır.
initState, State oluşturulduktan hemen sonra, ilk UI oluşturmadan önce çağrılır. Burada şunlar yapılır: denetleyicilerin başlatılması (TextEditingController, AnimationController), veri akışlarına abone olma (StreamSubscription), zamanlayıcı kurulumu ve alanların ilk başlatılması. Flutter belgelerine (Flutter.dev, 2026) göre, initState'te BuildContext.of() çağrılamaz — ağaç henüz tam olarak monte edilmemiştir.
didChangeDependencies, initState'ten sonra ve InheritedWidget bağımlılıkları her değiştiğinde çağrılır. Burası MediaQuery.of(context) çağırmak veya Theme'e abone olmak için uygun bir yerdir — uygulama çalışması sırasında değişebilecek değerler. Bir widget InheritedWidget kullanıyorsa, başlatma mantığı initState'te değil burada olmalıdır.
build, widget ağacını döndüren ana yöntemdir. initState'ten sonra, didChangeDependencies'ten sonra ve her setState'ten sonra çağrılır. didUpdateWidget, ebeveyn yeniden oluşturulduğunda ve yeni parametrelerle bir StatefulWidget ilettiğinde çağrılır. Burada eski ve yeni widget alanları karşılaştırılabilir ve gerekirse durum güncellenebilir.
dispose, yaşam döngüsünün son aşamasıdır. Burada tüm kaynaklar serbest bırakılır: akış abonelikleri iptal edilir, denetleyiciler kaldırılır, zamanlayıcılar iptal edilir. Dispose'ı çağırmamak bellek sızıntılarına yol açar. Dispose'tan sonra State ölü kabul edilir — içinde setState çağırmak bir istisna oluşturur.
StatefulWidget'ın çalışma mekanizması üç varlığın koordineli çalışmasına dayanır: Widget (hafif açıklama), Element (ara katman) ve State (veri depolama). Flutter açıklamada bir StatefulWidget ile karşılaştığında, createState'i çağıran ve State nesnesine bir referans depolayan StatefulElement oluşturur. Ebeveyn yeniden oluşturulduğunda, Flutter yeni widget'ı mevcut Element ile karşılaştırır — tür ve Key eşleşirse Element güncellenir ve State aynı kalır.
Durum yalnızca setState çağrısı aracılığıyla değiştirilir ve çerçeveye yeniden oluşturma gerektiğini bildirir. Anlaşılması önemlidir: setState durumu otomatik olarak değiştirmez — widget'ı yalnızca “kirli” olarak işaretler. Geliştirici, setState'e iletilen geri çağrıda State alanlarını bağımsız olarak günceller. Geri çağrı tamamlandıktan sonra Flutter build'i çağırır ve UI'yi günceller.
Dart/Flutter ekibine (Dart Language Specification, 2026) göre, bu ayrım, build çağrılmadan önce tüm durum değişikliklerinin eşzamanlı olarak gerçekleşmesini sağlayarak UI'nin kısmen güncellenmiş verileri görüntüleme durumunu ortadan kaldırır. Bu, Flutter'da arayüz tutarlılığının anahtar mekanizmasıdır.
Basit bir StatefulWidget — bir düğme tıklama sayacına bakalım. Temel modeli gösterir: State oluşturma, initState'te bir alanı başlatma, setState aracılığıyla değiştirme:
class CounterScreen extends StatefulWidget {
const CounterScreen({super.key});
@override
State<CounterScreen> createState() => _CounterScreenState();
}
class _CounterScreenState extends State<CounterScreen> {
int _count = 0;
void _increment() {
setState(() {
_count++;
});
}
@override
Widget build(BuildContext context) {
return Column(
children: [
Text('Count: $_count'),
ElevatedButton(
onPressed: _increment,
child: const Text('Artır'),
),
],
);
}
}
Asenkron veri yükleme ve yaşam döngüsü yönetimi ile bir örnek. StatefulWidget ağdan veri yükler ve yükleme durumunu görüntüler:
class UserProfilePage extends StatefulWidget {
final String userId;
const UserProfilePage({super.key, required this.userId});
@override
State<UserProfilePage> createState() => _UserProfilePageState();
}
class _UserProfilePageState extends State<UserProfilePage> {
UserModel? _user;
bool _isLoading = true;
@override
void initState() {
super.initState();
_loadUser();
}
Future<void> _loadUser() async {
final user = await UserService.fetchUser(widget.userId);
setState(() {
_user = user;
_isLoading = false;
});
}
@override
Widget build(BuildContext context) {
if (_isLoading) return const CircularProgressIndicator();
return Text('Merhaba, ${_user!.name}');
}
}
İkinci örnekte önemli bir nokta: initState asenkron bir işlem başlatır, ancak yöntemin kendisi asenkron değildir. Asenkronluk, ayrı bir _loadUser yöntemi içinde async/await aracılığıyla uygulanır ve istek tamamlandıktan sonra setState aracılığıyla durumu günceller. Bu yaklaşım, widget'ın veri almadan önce yükleme göstergesini doğru şekilde görüntülemesini sağlar.
StatefulWidget ve StatelessWidget arasındaki seçim yalnızca duruma sahip olmakla ilgili değildir. StatefulWidget, denetleyiciler, animasyonlar ve akışlarla çalışmak için gerekli olan initState, didChangeDependencies, didUpdateWidget ve dispose yöntemleriyle tam bir yaşam döngüsü sağlar. StatelessWidget ise bu yöntemlere sahip değildir ve çerçeve için her zaman daha hafiftir.
Flutter ekibinin önerisi (Flutter docs, 2026), durumu ağaçta yukarı taşıyarak (State Hoisting) veya durum yönetimi çözümleri (Riverpod, Bloc, Provider) kullanarak bir uygulamadaki StatefulWidget sayısını en aza indirmektir. Her StatefulWidget, öğe kaldırılana kadar yaşayan bir State nesnesi oluşturur — bu tür widget'lar ne kadar çoksa bellek yükü de o kadar yüksek olur.
| Kriter | StatefulWidget | StatelessWidget |
|---|---|---|
| Durum | Değişebilir | Değişmez |
| Yaşam döngüsü | 6 aşama | Yalnızca build |
| State nesnesi | Ayrıca oluşturulur | Gerekmez |
| setState | Mevcut | Mevcut değil |
| Abonelikler | initState/dispose | Desteklenmez |
| const kurucu | Sınırlı | Tam destekli |
| Bellek tüketimi | Daha yüksek | Daha düşük |
StatefulWidget, bir State nesnesi oluşturma ve sürdürme ihtiyacı nedeniyle StatelessWidget'tan daha fazla kaynak gerektirir. Ancak, StatefulWidget'ın doğru kullanımı, birkaç kurala uyulduğunda performans sorunlarına yol açmaz. İlk olarak, StatefulWidget'ın derin iç içe geçmesinden kaçının — her seviye ağaç geçişine ek yük ekler. İkinci olarak, karmaşık bir StatefulWidget'ı her biri durumun kendi kısmından sorumlu olan birkaç basit widget'a bölün.
Flutter Performans araştırmasına (Flutter.dev, Şubat 2026) göre FPS düşüşlerinin en yaygın nedeni, görüntülemeleri değişmeyen StatelessWidget'lar da dahil olmak üzere tüm alt öğeleri yeniden oluşturan bir ebeveyn widget'ta setState çağırmaktır. Çözüm, UI'nin değişebilir kısmını ayrı bir StatefulWidget'a çıkarmaktır, böylece setState yalnızca minimum gerekli widget'ları yeniden oluşturur.
State içinde const kullanmak bir diğer önemli tekniktir. Alt widget'lar const olarak bildirilirse, ebeveynde setState çağrıldığında Flutter bunları yeniden oluşturmaz. Bu, çerçeve üzerindeki yükü azaltır ve kare işleme süresini kısaltır.
Her setState çağrısı tam bir widget yeniden oluşturmayı tetikler. Durum yüksek frekansta değişiyorsa (örneğin, animasyon veya veri akışı), manuel olarak setState çağırmak yerine AnimatedBuilder, ValueListenableBuilder veya StreamBuilder kullanmayı düşünün. Bu widget'lar yeniden oluşturmayı optimize eder ve yalnızca gerçekten değişen UI kısmını günceller.
StatefulWidget ile ilk yaygın hata, dispose'tan sonra setState çağırmaktır. Bir widget ağaçtan kaldırıldığında State ölü kabul edilir ve herhangi bir setState çağrısı “setState called after dispose” istisnası oluşturur. Bu en çok, widget kaldırıldıktan sonra asenkron bir işlem tamamlandığında olur. Çözüm, setState çağırmadan önce mounted bayrağını kontrol etmek veya dispose'ta asenkron işlemleri iptal etmektir.
İkinci hata, build yönteminde ağır hesaplamalar yapmaktır. Build her setState'te ve her ebeveyn yeniden oluşturmada çağrıldığından, tüm hesaplamalar mümkün olduğunca hafif olmalıdır. Kaynak yoğun bir işlem gerekiyorsa, onu ayrı bir Isolate'e taşıyın veya sonucu bir State alanında önbelleğe alın.
Üçüncü hata, super.initState() ve super.dispose() çağırmamaktır. Bu yöntemleri geçersiz kılarken, geliştirici ebeveyn uygulamasını çağırmalıdır. Aksi takdirde, çerçeve Element durumunu düzgün yönetemez ve takip edilmesi zor hatalara yol açar.
mounted kontrol edinsuper.initState() ve super.dispose() çağırmayı unutmayınSıkça Sorulan Sorular
StatefulWidget, setState aracılığıyla durumunu değiştirebilir, bir yaşam döngüsüne (initState, dispose) sahiptir ve ayrı bir State nesnesi oluşturur. StatelessWidget durumu değiştiremez ve yaşam döngüsü yöntemlerine sahip değildir — yalnızca iletilen verileri görüntüler.
createState her StatefulElement örneği için tam olarak bir kez çağrılır. Ebeveyn birden çok kez yeniden oluşturulsa bile, widget'ın türü ve Key değişmediği sürece createState çağrılmaz — mevcut State nesnesi kullanılır.
Kaynaklar serbest bırakılmaz: denetleyiciler arka planda çalışmaya devam eder, akış abonelikleri aktif kalır, zamanlayıcılar iptal edilmez. Bu, bellek sızıntılarına yol açar ve dispose'tan sonra setState çağrılarına neden olarak istisna oluşturabilir.
Evet, StatefulWidget'ın kurucusu const olabilir. Ancak bu, StatelessWidget ile aynı avantajı sağlamaz — State nesnesi ilk eklemede yine de oluşturulacaktır. const, yalnızca widget'ın kendisini (hafif sarmalayıcı) etkiler, State'i etkilemez.
didUpdateWidget, ebeveyn yeni parametrelerle bir StatefulWidget ilettiğinde çağrılır. Bu, durumu yeni verilerle senkronize etmek için gereklidir — örneğin, parametrelerdeki userId değiştiyse, yeni kullanıcının profili yüklenmelidir.
Özet
Anahtar teslim bir mobil uygulama geliştireceğiz
IT Sectr, 2017'den beri girişimler ve işletmeler için iOS ve Android uygulamaları oluşturmaktadır. Size danışmanlık yapacak ve en iyi çözümü önereceğiz.
Ayrıca okuyun