setState pitfalls
- Flutter course
- Intermediate
- Lesson 3/99
- 4 min
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
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
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
Future<void> veriCek() async {
await Future.delayed(Duration(seconds: 1));
if (____) {
setState(() { _veri = 'hazır'; });
print(_veri);
}
}
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 |