CodeBlanks Logo Icon CodeBlanks

setState pitfalls

Learn async setState and the mounted check.

The async setState trap

If you call setState after awaiting a Future, the widget may no longer be on screen; the user may have navigated away. In that case setState throws an error.

Future.delayed(Duration(seconds: 2), () {
  setState(() { _data = 'ready'; });
});

To prevent this, you check mounted first.

mounted check

mounted tells whether the State object is currently in the widget tree. While it is true, setState is safe.

if (mounted) {
  setState(() { _data = result; });
}

After dispose is called, mounted becomes false.

Practice Load data async and call setState with mounted check

The veriCek method should wait 100 ms. Then check if (mounted) and use setState to set _veri to 'hazır', then call print(_veri).

Starter code

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)),
    );
  }
}

Sample solution

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)),
    );
  }
}

Expected output

hazır

Questions and answers

Review the lesson questions together with their answers. To test yourself, solve the lesson interactively.

1 What should be done before setState after an async operation?

  • After an async operation, mounted is checked before setState Correct answer
  • mounted is only used inside initState
  • mounted becomes true after State is disposed
  • mounted is always true

Explanation: After async the widget may have left the tree; before setState, if (mounted) checks that the State is still in the tree.

2 Add the mounted check

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

Explanation: After async, if (mounted) verifies the State is still in the tree before setState; if disposed, setState is skipped.

3 Async and mounted parts

Term Meaning
mounted Whether State is in the widget tree
async Keyword marking functions that can await
Future.delayed Runs a callback after a delay
if (mounted) Safe setState call after async

All lessons in Intermediate