StatefulWidget — egy Flutter widget változtatható állapottal, amely lehetővé teszi a UI számára, hogy reagáljon a felhasználói műveletekre, aszinkron eseményekre és adatfolyamokra. A hivatalos Flutter dokumentáció szerint (Flutter.dev, 2026), a StatefulWidget az alkalmazás összes interaktív eleméhez használatos: beviteli mezők, animációk, jelölőnégyzetek, kapcsolók és hálózatból adatokat betöltő képernyők. A StatelessWidget-től eltérően létrehoz egy külön State objektumot, amely a teljes életciklus alatt megmarad, és újjáépíthető a widget újbóli létrehozása nélkül.
Főbb pontok
StatefulWidget — egy Flutter osztály, amely megváltoztathatja állapotát a felhasználói műveletekre, rendszereseményekre vagy aszinkron műveletekre válaszul. A StatelessWidget-től eltérően a StatefulWidget nem közvetlenül jelenik meg — létrehoz egy State objektumot, amely a megjelenítésért felelős. A két osztályra (Widget és State) bontás lehetővé teszi a Flutter számára, hogy újjáépítse a UI-t a widget újbóli létrehozása nélkül, ami jelentős teljesítményelőnyt biztosít gyakori frissítések esetén.
A StatefulWidget architektúrája a «változtatható és változtathatatlan szétválasztása» mintát követi: maga a widget változtathatatlan marad (mint a StatelessWidget), míg az összes változtatható állapot egy külön State objektumban tárolódik. Ez lehetővé teszi a Flutter számára a widgetek újrafelhasználását típus és Key alapján történő összehasonlítással, miközben megtartja az aktuális állapotot az újjáépítések között.
A Google szerint (Flutter Architectural Overview, 2026) a StatefulWidget optimális azokhoz a forgatókönyvekhez, ahol az állapot többször változik a widget élettartama során: szövegmezők, animációk, időzítők, adatfolyamok, aszinkron betöltések. Egyszeri inicializáláshoz a StatelessWidget elegendő.
StatefulWidget kötelező, ha a widgetnek reagálnia kell külső eseményekre: gombnyomás, HTTP-kérés befejezése, adatbázis-frissítés, WebSocket feliratkozás. Szükséges továbbá animációs widgetekhez, vezérlőkkel ellátott szövegmezőkhöz és fókuszt kezelő komponensekhez. Ha a widget csak adatokat jelenít meg és nem generál eseményeket — használjon StatelessWidget-et.
A StatefulWidget két osztályból áll: magából a StatefulWidget-ből (könnyű, változtathatatlan) és a State-ből (nehéz, változtatható). A keretrendszer a createState() metóduson keresztül hozza létre a State-t, amely egyszer hívódik meg a fába történő beágyazáskor. A State a widget tulajdonságon keresztül kap referenciát a widgetre, és az életciklus bármely pontján hozzáférhet annak mezőihez.
Az életciklus StatefulWidget hat fő szakaszból áll, amelyek mindegyike felülírható metódust biztosít specifikus feladatok végrehajtásához. Ezen szakaszok megértése kritikus fontosságú az erőforrásokkal való helyes munkához és a memóriaszivárgások elkerüléséhez.
createState — az életciklus első metódusa, amely a StatefulWidget fába történő beágyazásakor hívódik meg. Vissza kell adnia a widgethez társított State új példányát. Ez a metódus pontosan egyszer hívódik meg az elem teljes élettartama alatt. Fontos, hogy ne végezzünk nehéz műveleteket itt — a createState-nek a lehető legkönnyebbnek kell lennie.
initState — közvetlenül a State létrehozása után hívódik meg, az első UI-építés előtt. Itt történik: vezérlők inicializálása (TextEditingController, AnimationController), adatfolyamokra való feliratkozás (StreamSubscription), időzítők beállítása és a mezők kezdeti inicializálása. A Flutter dokumentáció szerint (Flutter.dev, 2026) az initState-ben nem hívható meg a BuildContext.of() — a fa még nincs teljesen felcsatolva.
didChangeDependencies — az initState után és minden alkalommal meghívódik, amikor az InheritedWidget függőségei megváltoznak. Ez a megfelelő hely a MediaQuery.of(context) meghívásához vagy a Theme-re való feliratkozáshoz — olyan értékek, amelyek az alkalmazás futása közben megváltozhatnak. Ha a widget InheritedWidget-ot használ, az inicializálási logikának itt kell lennie, nem az initState-ben.
build — a fő metódus, amely visszaadja a widget fát. Az initState után, a didChangeDependencies után és minden setState után hívódik meg. didUpdateWidget akkor hívódik meg, amikor a szülő újjáépíti és új paraméterekkel adja át a StatefulWidget-et. Itt összehasonlíthatja a widget régi és új mezőit, és szükség esetén frissítheti az állapotot.
dispose — az életciklus utolsó szakasza. Itt szabadulnak fel az összes erőforrás: leiratkozás a folyamokról, vezérlők törlése, időzítők lemondása. A dispose elmulasztása memóriaszivárgáshoz vezet. A dispose után a State halottnak tekintendő — a benne lévő setState hívás kivételt dob.
A StatefulWidget működési mechanizmusa három entitás összehangolt munkáján alapul: Widget (könnyű leírás), Element (köztes réteg) és State (adat tároló). Amikor a Flutter StatefulWidget-et talál a leírásban, létrehoz egy StatefulElement-et, amely meghívja a createState-t és tárolja a referenciát a State objektumra. A szülő újjáépítésekor a Flutter összehasonlítja az új widget-et az aktuális Element-tel — ha a típus és a Key megegyezik, az Element frissül, a State pedig változatlan marad.
Az állapot csak a setState meghívásával változik, amely értesíti a keretrendszert az újjáépítés szükségességéről. Fontos megérteni: a setState nem változtatja meg automatikusan az állapotot — csak «piszkosnak» jelöli a widget-et. A fejlesztő maga frissíti a State mezőit a setState-nek átadott callback-ben. A callback befejezése után a Flutter meghívja a build-t és frissíti a UI-t.
A Dart/Flutter csapat szerint (Dart Language Specification, 2026) ez a szétválasztás garantálja, hogy az összes állapotváltozás szinkron módon történjen a build meghívása előtt, kizárva azt a helyzetet, amikor a UI részlegesen frissített adatokat jelenít meg. Ez a felület konzisztenciájának kulcsmechanizmusa a Flutter-ben.
Vegyünk egy egyszerű StatefulWidget-et — egy gomb kattintásszámlálóját. Ez bemutatja az alapmintát: a State létrehozása, a mező inicializálása az initState-ben, változtatás a setState segítségével:
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('Szám: $_count'),
ElevatedButton(
onPressed: _increment,
child: const Text('Növelés'),
),
],
);
}
}
Példa aszinkron adatbetöltéssel és életciklus-kezeléssel. A StatefulWidget adatokat tölt be a hálózatból és megjeleníti a betöltési állapotot:
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('Helló, ${_user!.name}');
}
}
A második példában fontos megjegyezni: az initState elindít egy aszinkron műveletet, de maga a metódus nem aszinkron. Az aszinkronitás az async/await segítségével valósul meg a külön _loadUser metóduson belül, amely a kérés befejezése után a setState segítségével frissíti az állapotot. Ez a megközelítés garantálja, hogy a widget helyesen jelenítse meg a betöltés jelzőt az adatok megérkezése előtt.
A StatefulWidget és a StatelessWidget közötti választás nem csupán az állapot meglétének kérdése. A StatefulWidget teljes életciklust biztosít az initState, didChangeDependencies, didUpdateWidget és dispose metódusokkal, ami szükséges a vezérlőkkel, animációkkal és folyamokkal való munkához. A StatelessWidget viszont nem rendelkezik ezekkel a metódusokkal, és mindig könnyebb a keretrendszer számára.
A Flutter csapat ajánlása (Flutter docs, 2026) — minimalizálja a StatefulWidget-ek számát az alkalmazásban az állapot fában történő felemelésével (State Hoisting) vagy állapotkezelő megoldások használatával (Riverpod, Bloc, Provider). Minden StatefulWidget létrehoz egy State objektumot, amely az elem eltávolításáig él — minél több ilyen widget van, annál nagyobb a memóriaterhelés.
| Szempont | StatefulWidget | StatelessWidget |
|---|---|---|
| Állapot | Változtatható | Változtathatatlan |
| Életciklus | 6 szakasz | Csak build |
| State objektum | Külön létrehozva | Nem szükséges |
| setState | Elérhető | Nem elérhető |
| Feliratkozások | initState/dispose | Nem támogatott |
| const konstruktor | Korlátozott | Teljesen támogatott |
| Memóriafogyasztás | Magasabb | Alacsonyabb |
StatefulWidget több erőforrást igényel, mint a StatelessWidget a State objektum létrehozásának és karbantartásának szükségessége miatt. Azonban a StatefulWidget helyes használata nem vezet teljesítményproblémákhoz, ha néhány szabályt betartanak. Először is, kerülje a StatefulWidget mély egymásba ágyazását — minden szint többletterhelést ad a fa bejárásához. Másodszor, ossza fel az összetett StatefulWidget-et több egyszerű widgetre, amelyek mindegyike az állapot egy-egy részéért felelős.
A Flutter Performance kutatás szerint (Flutter.dev, 2026. február) az FPS csökkenésének leggyakoribb oka a setState meghívása a szülő widget-ben, amely az összes leszármazottat újjáépíti, beleértve azokat a StatelessWidget-eket is, amelyek nem változtatták meg megjelenítésüket. A megoldás — helyezze át a UI változtatható részét egy külön StatefulWidget-be, hogy a setState csak a minimálisan szükséges widget-eket építse újjá.
A const használata a State-en belül egy másik fontos technika. Ha a gyermek widget-ek const-ként vannak deklarálva, a Flutter nem építi újjá őket a setState szülőben történő meghívásakor. Ez csökkenti a keretrendszer terhelését és lerövidíti a képkocka megjelenítési idejét.
Minden setState hívás a widget teljes újjáépítését indítja el. Ha az állapot nagy gyakorisággal változik (például animáció vagy adatfolyam), fontolja meg az AnimatedBuilder, ValueListenableBuilder vagy StreamBuilder használatát a kézi setState hívás helyett. Ezek a widget-ek optimalizálják az újjáépítést, csak a ténylegesen megváltozott UI részt frissítve.
Az első gyakori hiba a StatefulWidget-tel — a setState meghívása a dispose után. Amikor a widget eltávolításra kerül a fából, a State halottnak tekintendő, és minden setState hívás a «setState called after dispose» kivételt dobja. Leggyakrabban ez akkor történik, amikor egy aszinkron művelet a widget eltávolítása után fejeződik be. A megoldás — ellenőrizze a mounted jelzőt a setState meghívása előtt, vagy mondja le az aszinkron műveleteket a dispose-ban.
A második hiba — nehéz számítások végrehajtása a build metódusban. Mivel a build minden setState és minden szülő újjáépítésekor meghívódik, minden számításnak a lehető legkönnyebbnek kell lennie. Ha erőforrás-igényes műveletet kell végrehajtani — helyezze át egy külön Isolate-ba, vagy gyorsítótárazza az eredményt egy State mezőben.
A harmadik hiba — a super.initState() és a super.dispose() elmulasztása. Ezen metódusok felülírásakor a fejlesztő köteles meghívni a szülő implementációt. Ha ez nem történik meg, a keretrendszer nem tudja megfelelően kezelni az Element állapotát, ami nehezen megtalálható hibákhoz vezet.
mounted jelzőt a setState előtt aszinkron callback-ekbensuper.initState() és super.dispose() metódusokatGyakran Ismételt Kérdések
StatefulWidget megváltoztathatja állapotát a setState segítségével, életciklussal rendelkezik (initState, dispose) és létrehoz egy külön State objektumot. A StatelessWidget nem tudja megváltoztatni az állapotát és nem rendelkezik életciklus metódusokkal — csak a kapott adatokat jeleníti meg.
createState pontosan egyszer hívódik meg minden StatefulElement példányhoz. Még ha a szülő többször újjá is épül, amíg a widget típusa és Key-je nem változik, a createState nem hívódik meg — a meglévő State objektum kerül felhasználásra.
Az erőforrások nem szabadulnak fel: a vezérlők tovább működnek a háttérben, a folyamfeliratkozások aktívak maradnak, az időzítők nem mondódnak le. Ez memóriaszivárgáshoz vezet, és a dispose utáni setState hívást okozhat, ami kivételt dob.
Igen, a konstruktor StatefulWidget lehet const. Ez azonban nem nyújtja ugyanazt az előnyt, mint a StatelessWidget esetében — a State objektum akkor is létrejön az első beágyazáskor. A const csak magára a widget-re (a könnyű burkolóra) hat, nem a State-re.
didUpdateWidget akkor hívódik meg, amikor a szülő új paraméterekkel adja át a StatefulWidget-et. Ez szükséges az állapot és az új adatok szinkronizálásához — például ha a userId megváltozott a paraméterekben, be kell tölteni az új felhasználó profilját.
Összefoglalás
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