CodeBlanks Logo Icon CodeBlanks

setState tuzakları

Async sonrası setState ve mounted kontrolünü öğrenirsin.

Async sonrası setState tuzağı

Bir Future bekledikten sonra setState çağırırsan, widget artık ekranda olmayabilir; kullanıcı başka sayfaya geçmiş olabilir. Bu durumda setState hata fırlatır.

Future.delayed(Duration(seconds: 2), () {
  setState(() { _veri = 'hazır'; });
});

Bunu önlemek için mounted kontrolü yaparsın.

mounted kontrolü

mounted, State nesnesinin o anda widget ağacında olup olmadığını söyler. true iken setState güvenlidir.

if (mounted) {
  setState(() { _veri = sonuc; });
}

dispose çağrıldıktan sonra mounted false olur.

Uygulama Async veri yükle ve mounted ile setState çağır

veriCek metodu 100 ms beklesin. Sonra if (mounted) kontrolü yapıp setState ile _veri'yi 'hazır' yap ve print(_veri) çağır.

Başlangıç kodu

main.dart
import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(home: VeriEkrani());
  }
}

class VeriEkrani extends StatefulWidget {
  @override
  _VeriEkraniState createState() => _VeriEkraniState();
}

class _VeriEkraniState extends State<VeriEkrani> {
  String _veri = 'yükleniyor';

  @override
  void initState() {
    super.initState();
    veriCek();
  }

  Future<void> veriCek() async {
    await Future.delayed(Duration(milliseconds: 100));
    // mounted kontrolü yap, setState ile veriyi güncelle ve ekrana yazdır
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(child: Text(_veri)),
    );
  }
}

Örnek çözüm

main.dart
import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(home: VeriEkrani());
  }
}

class VeriEkrani extends StatefulWidget {
  @override
  _VeriEkraniState createState() => _VeriEkraniState();
}

class _VeriEkraniState extends State<VeriEkrani> {
  String _veri = 'yükleniyor';

  @override
  void initState() {
    super.initState();
    veriCek();
  }

  Future<void> veriCek() async {
    await Future.delayed(Duration(milliseconds: 100));
    if (mounted) {
      setState(() {
        _veri = 'hazır';
      });
      print(_veri);
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(child: Text(_veri)),
    );
  }
}

Beklenen çıktı

hazır

Soru ve cevaplar

Dersin sorularını cevaplarıyla birlikte inceleyebilirsin. Kendini denemek istersen dersi interaktif olarak çöz.

1 Async bir işlem sonrası setState'ten önce ne yapılmalı?

  • Async bir işlem sonrası setState'ten önce mounted kontrolü yapılır Doğru cevap
  • mounted yalnızca initState içinde kullanılır
  • mounted, State dispose edildikten sonra true olur
  • mounted her zaman true'dur

Açıklama: Async sonrası widget ağaçtan çıkmış olabilir; setState'ten önce if (mounted) ile State'in hâlâ ağaçta olduğu kontrol edilir.

2 mounted kontrolünü ekle

Soru
Future<void> veriCek() async {
  await Future.delayed(Duration(seconds: 1));
  if (____) {
    setState(() { _veri = 'hazır'; });
    print(_veri);
  }
}
Cevap
Future<void> veriCek() async {
  await Future.delayed(Duration(seconds: 1));
  if (mounted) {
    setState(() { _veri = 'hazır'; });
    print(_veri);
  }
}

Açıklama: Async sonrası setState'ten önce if (mounted) ile State'in hâlâ ağaçta olduğu doğrulanır; dispose edildiyse setState atlanır.

3 Async ve mounted parçaları

Kavram Anlamı
mounted State'in widget ağacında olup olmadığı
async Beklenebilen fonksiyonları işaretleyen anahtar kelime
Future.delayed Belirli süre sonra callback çalıştırır
if (mounted) Async sonrası setState'in güvenli çağrısı

Orta seviye bölümündeki tüm dersler