setState() — a State osztály kulcsmetódusa a Flutter-ben, amely értesíti a keretrendszert az adatok változásáról és elindítja a felület újraépítését. A hivatalos Flutter dokumentáció szerint (Flutter.dev, 2026) a setState a reaktivitás fő mechanizmusa a StatefulWidget-ben: hívása nélkül az UI nem tud a State mezők változásairól, és az előző állapotban marad. A metódus egy VoidCallback-et fogad, amelyen belül a fejlesztő módosítja a változó mezőket, majd a Flutter automatikusan meghívja a build-et a widget újraépítéséhez.
Főbb pontok
setState() — a State osztály beépített metódusa a Flutter-ben, amely a keretrendszer értesítésére szolgál arról, hogy a widget belső állapota megváltozott és az UI újraépítése szükséges. A setState hívása nélkül a Flutter nem tud a változásokról — még ha a State mezők módosultak is, a felület változatlan marad a szülő általi következő kényszerített újraépítésig.
A metódus aláírása: void setState(VoidCallback fn). A callback szinkron módon hajtódik végre a setState-en belül, és csak a befejezése után kerül a State dirty-nek jelölésre. Ez garantálja, hogy minden változás atomi módon kerül alkalmazásra az újraépítés előtt. A Dart Language Specification (Dart Team, 2026) szerint a setState atomicitása megakadályozza a versenyhelyzetet, ahol a build részlegesen frissített állapotot láthatna.
A setState nem fogad argumentumokat, nem ad vissza értéket és nem írható felül. Ez a State osztály végleges (sealed) metódusa. A fejlesztő nem változtathatja meg a viselkedését — csak rendeltetésszerűen használhatja. A setState State-en kívüli (pl. másik osztályból történő) meghívása lehetetlen, mivel a metódus a State osztályban van deklarálva.
Egy gyakori tévhit — azt gondolni, hogy a setState maga változtatja meg az állapotot. Ez nem igaz. A setState csak meghívja az átadott callback-et (amelyben a fejlesztő módosítja a mezőket), majd jelzi a keretrendszernek a build szükségességét. A callback kötelező — null vagy üres callback átadása hibát okoz.
A setState() működési mechanizmusa négy szakaszra osztható. Első — a metódus meghívása callback-kel. Második — a callback szinkron végrehajtása, melyen belül a State mezők módosulnak. Harmadik — a State dirty-nek jelölése a speciális _dirty mezőben. Negyedik — az aktuális microtask végén a Flutter végigjárja az összes dirty elemet és meghívja azok build-jét a fában való megjelenés sorrendjében.
Fontos részlet: a setState nem hívja meg azonnal a build-et. A Flutter kötegelt frissítési stratégiát használ: az összes dirty elem összegyűjtésre kerül és egy képkockában épül újra. Ez azt jelenti, hogy ha a setState többször meghívásra kerül ugyanazon szinkron blokkon belül, a build csak egyszer hajtódik végre — az összes változás befejezése után. Ez az optimalizálás megakadályozza a többszörös újraépítést egy képkockán belül.
A Flutter Engine Team (Google, 2025) szerint a dirty-zászlók mechanizmusa a BuildOwner._dirtyElements bejárásán alapul. Minden dirty StatefulElement hozzáadásra kerül a listához és a képkocka frissítési szakaszában feldolgozásra kerül. Ha a widget a feldolgozás előtt eltávolításra került a fából, automatikusan kizárásra kerül a dirty elemek listájából.
A setState() alap példája számláló növeléssel. A helyes használatot mutatja: mező módosítása a callback-en belül:
class _CounterState extends State<CounterWidget> {
int _count = 0;
void _increment() {
setState(() {
_count++; // mező mutációja a callback-en belül
});
}
@override
Widget build(BuildContext context) {
return ElevatedButton(
onPressed: _increment,
child: Text('$_count'),
);
}
}
Példa szövegmezővel és vezérlővel — setState() a jelszó láthatóságának kezelésére:
class _PasswordFieldState extends State<PasswordField> {
bool _obscured = true;
final _controller = TextEditingController();
void _toggleVisibility() {
setState(() {
_obscured = !_obscured;
});
}
@override
Widget build(BuildContext context) {
return TextField(
controller: _controller,
obscureText: _obscured,
decoration: InputDecoration(
suffixIcon: IconButton(
icon: Icon(_obscured ? Icons.visibility : Icons.visibility_off),
onPressed: _toggleVisibility,
),
),
);
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
}
Ebben a példában a setState() csak a _obscured logikai mezőt változtatja meg, ami a TextField újraépítését okozza új ikonnal és megjelenítési móddal. A szövegvezérlő nem jön létre újra — egyszer kerül inicializálásra az initState-ben és felszabadításra a dispose-ban.
Ha több mezőt kell módosítani, az összes változás egy setState-en belül történik. Ez garantálja, hogy a build konzisztens állapotot lát:
setState(() {
_isLoading = false;
_items = newItems;
_error = null;
});
Három mező módosul egy callback-ben — a build egyszer hajtódik végre és egyszerre látja az összes változást. Ha minden hívás külön setState lenne, a build akkor is egyszer hajtódna végre a dirty elemek kötegelt feldolgozásának köszönhetően.
A setState() egyik legfontosabb árnyalata — a viselkedése aszinkron műveletekkel. A setState callback szinkron módon hajtódik végre, de ha azon belül await kerül meghívásra, az await utáni kód a setState befejezése után hajtódik végre. Ez azt jelenti, hogy az await utáni mezőváltozások nem kerülnek rögzítésre az aktuális setState által.
Helyes megközelítés: az aszinkron művelet a setState-en kívül hajtódik végre, és a setState a befejezése után kerül meghívásra. Az eredmény fogadása és a setState hívása közötti összes kód szinkron kontextusban hajtódik végre az await után:
// HELYES: await a setState-en kívül
Future<void> _loadData() async {
final result = await ApiService.fetchData();
setState(() {
_data = result;
_isLoading = false;
});
}
// ROSSZ: await a setState-en belül — nincs frissítési garancia
void _loadDataWrong() {
setState(() async {
_data = await ApiService.fetchData(); // a setState visszatér az await befejezése előtt
_isLoading = false; // ezt a kódot nem rögzíti a setState
});
}
A Flutter dokumentáció szerint (Dart async patterns, 2026) az async-callback setState-nek való átadása antipattern, mivel a setState VoidCallback-et (szinkron függvényt) vár, míg az async függvény egy Future-t ad vissza, amely figyelmen kívül marad. Az első await utáni változások egy ilyen callback-ben nem kerülnek helyesen feldolgozásra a keretrendszer által.
Aszinkron művelet után a setState() hívása előtt mindig ellenőrizze a mounted-et:
if (mounted) {
setState(() => _data = data);
}
Ha a widget az aszinkron művelet végrehajtása során eltávolításra került a fából, a mounted false lesz és a setState nem kerül meghívásra. Ez megakadályozza a kivételt és az erőforrás-szivárgást.
setState() — kényelmes, de potenciálisan költséges mechanizmus, ha meggondolatlanul használják. Minden setState hívás újraépíti az egész widget-et és annak összes leszármazottját (ha nem const). Mély fákban vagy gyakori hívások esetén ez FPS-csökkenéshez vezethet.
Fő optimalizálási stratégiák: minimalizálni az újraépítési területet (a változó UI részek külön StatefulWidget-ekbe helyezése), const használata a változatlan leszármazottakhoz és a setState hívásának kerülése szülő widget-ekben, ha csak egy kis UX részlet változott. Ha az állapot nagy gyakorisággal frissül (animáció, adatfolyam), fontolja meg az AnimatedBuilder vagy ValueListenableBuilder használatát.
A Flutter Performance Best Practices (Flutter.dev, 2026. február) szerint a valós alkalmazások profilozása azt mutatja, hogy az összes setState hívás akár 40%-a helyettesíthető const gyermek widget-ekkel vagy reaktív builderekkel (StreamBuilder, FutureBuilder). Ez 15–25%-kal csökkenti az átlagos képkocka-építési időt.
| Forgatókönyv | Alternatíva | Előny |
|---|---|---|
| Animáció | AnimatedBuilder | Csak az animált widget-et építi újra |
| Adatfolyam | StreamBuilder | Reagál a folyam minden elemére |
| Jövőbeli eredmény | FutureBuilder | Kezeli a betöltési/hiba állapotokat |
| Helyi érték | ValueListenableBuilder | Reagál egy érték változására |
A setState() sokoldalúsága ellenére nagy projektekben főként helyi állapothoz használják. Globális vagy megosztott állapothoz speciális megoldásokat használnak, amelyek mindegyike helyettesíti vagy becsomagolja a setState-et.
A Provider a ChangeNotifier + notifyListeners-t használja a setState analógjaként, de több widget feliratkozási lehetőségével. A Bloc a Streams-t használja — az állapot események StreamController-hez adásával változik. A Riverpod kombinálja a megközelítéseket, helyi (StateProvider) és aszinkron (AsyncNotifier) kezelést kínálva a StatefulWidget-hez való kötődés nélkül. Mindhárom megközelítés kiküszöböli a setState manuális hívásának szükségességét — az UI frissítése automatikusan történik az adatok változásakor.
A Flutter Community Survey 2025 (Flutter Foundation, 2025. december) szerint a fejlesztők 74%-a használ legalább egy állapotkezelő eszközt a setState mellett. Ugyanakkor 92% továbbra is használ setState-et a szövegmező, jelölőnégyzet vagy egyszerű számláló helyi adataihoz — ez tekinthető bevált gyakorlatnak (best practice).
Az első és legveszélyesebb hiba — a setState hívása dispose után. Az aszinkron művelet az initState-ben indult, a felhasználó elhagyta a képernyőt, a widget eltávolításra került és az aszinkron művelet callback-je meghívja a setState-et — az alkalmazás összeomlik egy kivétellel. Megoldás — mindig ellenőrizze a mounted-et hívás előtt.
Második hiba — a setState hívása a build-en belül. Ez végtelen ciklushoz vezet: build → setState → dirty → build → setState → ... A Flutter nem blokkolja az ilyen hívást (StackOverflowError-t kap). A setState csak eseményre válaszul hívható (gombnyomás, Future befejeződése, adatok fogadása folyamból).
Harmadik hiba — a State mezők módosítása a setState hívása nélkül. A fejlesztő _count++-t ír és elvárja, hogy az UI frissüljön. A Flutter nem tudja automatikusan követni a mezőváltozásokat — explicit jelre van szüksége a setState-en keresztül. Ez alapvető különbség az olyan reaktív keretrendszerektől, mint a Vue.js, ahol az adatváltozás automatikusan frissítést triggerel.
Negyedik hiba — a setState hívása aszinkron callback-kel (async-lambda). Ahogy az aszinkronitásról szóló részben leírtuk, az await utáni változások nem kerülnek rögzítésre, ami nehezen reprodukálható hibákhoz vezet. Használjon szinkron callback-et és hívja a setState-et await után.
mounted-etGyakran Ismételt Kérdések
setState() értesíti a Flutter-t, hogy a StatefulWidget belső adatai megváltoztak és az UI-t újra kell építeni. A metódus fogad egy callback-et, szinkron módon végrehajtja, piszkosnak jelöli a widget-et és a build meghívását tervezi a következő képkockában.
Az UI nem frissül. A Flutter nem követi automatikusan a mezőváltozásokat. A mező értéke a memóriában megváltozik, de a widget az előző állapotban marad a szülő általi következő kényszerített újraépítésig.
Nem. Ez végtelen ciklushoz vezet: a build meghívja a setState-et, amely piszkosnak jelöli a widget-et és újra meghívja a build-et. A Flutter nem blokkolja az ilyen helyzetet — az alkalmazás StackOverflowError-ral összeomlik.
A build egyszer hajtódik végre. A Flutter összegyűjti az összes dirty elemet és kötegelve építi újra a képkocka végén. A második setState az első feldolgozása előtt egyszerűen hozzáadja az elemet ugyanahhoz a dirty elemek listájához — nem történik ismételt build.
mounted — egy logikai jelző, amely mutatja, hogy a widget még a fában van. Ha aszinkron művelet után a mounted ellenőrzése nélkül hívja meg a setState-et, és a widget már eltávolításra került — az alkalmazás összeomlik a „setState called after dispose” kivétellel.
Összefoglaló
Kulcsrakész mobilalkalmazást fejlesztünk
Az IT Sectr 2017 óta készít iOS és Android alkalmazásokat induló vállalkozásoknak és vállalkozásoknak. Tanácsot adunk, és a legjobb megoldást javasoljuk.
Olvassa el is