State — het centrale object voor gegevensbeheer in Flutter, geassocieerd met StatefulWidget en verantwoordelijk voor het opslaan van wijzigbare informatie en het bouwen van de interface. Volgens de officiële Flutter-documentatie (Flutter.dev, 2026) bestaat State gedurende de hele levenscyclus van de widget en overleeft het herbouw, waardoor gegevensconsistentie tussen UI-updates wordt gegarandeerd. In tegenstelling tot de widget zelf, kan State zijn velden wijzigen en herbouw initiëren door setState aan te roepen.
Belangrijkste
State — is een object in de Flutter-architectuur dat de wijzigbare gegevens van StatefulWidget opslaat en bepaalt hoe deze gegevens worden weergegeven in de interface. Elke StatefulWidget maakt bij het inbedden in de boom precies één State-object aan via de createState-methode. State bestaat onafhankelijk van de widget: als de ouder de StatefulWidget herbouwt met nieuwe parameters, blijft State hetzelfde en ontvangt het de bijgewerkte widget via de eigenschap widget.
Volgens Flutter Architectural Overview (Google, 2026) is de scheiding van Widget en State een bewuste architectuurbeslissing waarmee het framework boom-elementen kan hergebruiken. De widget (lichte beschrijving) kan meerdere keren worden gemaakt en vernietigd, maar State (zwaar object met gegevens) blijft in het geheugen zolang het element zich in de boom bevindt. Dit voorkomt gegevensverlies bij frequente herbouw van bovenliggende widgets.
State implementeert de StatefulWidget-interface via een generiek: class _MyState extends State<MyWidget>. De generiek koppelt State aan een specifiek StatefulWidget-type en biedt typeveilige toegang tot de velden via de eigenschap widget.
Het State-object wordt opgeslagen in StatefulElement — de tussenlaag tussen Widget en RenderObject. StatefulElement maakt State aan via createState, bewaart de verwijzing ernaar en geeft State door als eigenaar. Het element wordt pas vernietigd wanneer de widget uit de boom wordt verwijderd — tot dat moment leeft State in het geheugen.
De levenscyclus van State is deterministisch en bestaat uit een strikte volgorde van aanroepen. Het begrijpen van deze volgorde is de basis voor correct werken met bronnen en het voorkomen van geheugenlekken.
initState wordt als eerste aangeroepen bij het aanmaken van State. In deze methode worden controllers, abonnementen op gegevensstromen, timers en beginwaarden van velden geïnitialiseerd. Het aanroepen van super.initState() in de eerste regel is verplicht. In de initState-fase is de widgetboom nog niet volledig gemonteerd, dus methoden zoals MediaQuery.of(context) kunnen onjuist werken.
didChangeDependencies wordt aangeroepen na initState en bij elke wijziging van InheritedWidget-afhankelijkheden. Hier, en niet in initState, moeten MediaQuery.of(context) of Theme.of(context) worden aangeroepen, omdat de boom op dit moment al is gemonteerd. Deze methode wordt ook aangeroepen als de widget naar een andere context wordt verplaatst waar InheritedWidget andere waarden biedt.
build — de hoofdmethode van State die de widgetboom retourneert. Aangeroepen na initState, na didChangeDependencies en na elke setState. De build-methode mag geen neveneffecten hebben — ze beschrijft alleen de interface op basis van de huidige waarden van de State-velden.
didUpdateWidget wordt aangeroepen wanneer de ouder de StatefulWidget herbouwt met nieuwe parameters. State krijgt toegang tot de oude widget via oldWidget en kan deze vergelijken met de nieuwe. Als de parameters zijn gewijzigd, kan de toestand worden bijgewerkt, kunnen nieuwe gegevens worden geladen of de animatie opnieuw worden gestart.
dispose — de afsluitende methode waarin alle bronnen worden vrijgegeven: controllers, abonnementen, timers. Na dispose wordt State als dood gemarkeerd: mounted retourneert false, het aanroepen van setState genereert een uitzondering. Het aanroepen van super.dispose() in de laatste regel van de methode is verplicht.
| Methode | Wanneer aangeroepen | Verplichte super |
|---|---|---|
| initState | Bij het aanmaken van State | Ja, in de eerste regel |
| didChangeDependencies | Na initState en bij wijziging van InheritedWidget | Ja |
| build | Na initState, didChangeDependencies, setState | Nee |
| didUpdateWidget | Bij nieuwe widget van de ouder | Ja |
| setState | Bij aanroep door de ontwikkelaar | Nee |
| dispose | Bij verwijdering uit de boom | Ja, in de laatste regel |
Het werkingsmechanisme van State is gebaseerd op drie kernprincipes: associatie met Element, reactiviteit via setState en toegang tot de ouder via de eigenschap widget. Wanneer Flutter de elementenboom bouwt en StatefulElement tegenkomt, roept het createState van de gekoppelde widget aan. De aangemaakte State wordt opgeslagen in het element en blijft bestaan totdat het element wordt verwijderd.
Bij het aanroepen van setState markeert State zichzelf als „vuil“ (dirty) en plant herbouw voor het volgende frame. Belangrijk: setState roept build niet onmiddellijk aan — het registreert alleen de noodzaak tot herbouw. Flutter verzamelt alle vuile elementen in het huidige frame en herbouwt ze in batch, wat de prestaties optimaliseert. Na de build-aanroep keert State terug naar de „schone“ (clean) toestand.
De eigenschap widget stelt State in staat de parameters te lezen die aan de constructor van StatefulWidget zijn doorgegeven. Omdat StatefulWidget onveranderlijk is (zoals StatelessWidget), veranderen de velden niet — bij wijziging van parameters maakt de ouder een nieuwe widget aan en State ontvangt deze via didUpdateWidget. Dit garandeert dat State altijd werkt met actuele gegevens van de ouder.
Basisvoorbeeld van State met een veld dat door een timer wordt gewijzigd. Demonstreert initState, setState en dispose:
class _TimerWidgetState extends State<TimerWidget> {
int _seconds = 0;
Timer? _timer;
@override
void initState() {
super.initState();
_timer = Timer.periodic(
const Duration(seconds: 1),
(_) => setState(() => _seconds++),
);
}
@override
void dispose() {
_timer?.cancel();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Text('$_seconds seconden verstreken');
}
}
Voorbeeld met gebruik van de eigenschap widget voor toegang tot parameters van de ouder en reactie op wijzigingen via didUpdateWidget:
class _GreetingState extends State<GreetingWidget> {
String _displayName = '';
@override
void initState() {
super.initState();
_displayName = _formatName(widget.name);
}
@override
void didUpdateWidget(GreetingWidget oldWidget) {
super.didUpdateWidget(oldWidget);
if (widget.name != oldWidget.name) {
setState(() {
_displayName = _formatName(widget.name);
});
}
}
String _formatName(String name) => name.trim().isEmpty ? 'Guest' : name;
@override
Widget build(BuildContext context) {
return Text('Hallo, $_displayName!');
}
}
In het tweede voorbeeld volgt State de wijziging van de invoerparameter name en herformateert de weergave alleen bij een echte wijziging. Zonder controle van widget.name != oldWidget.name zou de methode worden aangeroepen bij elke herbouw van de ouder, zelfs als de naam niet is gewijzigd — onnodig werk voor het framework.
State en StatefulWidget zijn twee verschillende klassen in de Flutter-architectuur met verschillende rollen. StatefulWidget — is een lichte onveranderlijke wrapper die de configuratie van de widget beschrijft en State aanmaakt. State — is een zwaar object dat wijzigbare gegevens opslaat, abonnementen beheert en UI bouwt. Deze scheiding stelt Flutter in staat widgets te vernietigen en aan te maken zonder toestandsverlies.
Alle velden van StatefulWidget moeten final zijn en in de constructor worden ingesteld — ze veranderen niet na aanmaak. State daarentegen kan zijn velden op elk moment wijzigen, maar alle wijzigingen moeten worden voorafgegaan door een setState-aanroep, zodat Flutter op de hoogte wordt gesteld van de noodzaak tot herbouw. Dit is het belangrijkste verschil: StatefulWidget is „wat te tonen“, State — „hoe te tonen en welke gegevens te gebruiken“.
Volgens Flutter source code analysis (Flutter SDK, 2026) bevat StatefulWidget slechts één verplicht veld — createState, terwijl State toegang heeft tot BuildContext, zich kan abonneren op stromen, animaties en controllers kan beheren. Het wordt aanbevolen StatefulWidget zo eenvoudig mogelijk te houden en alle logica naar State te verplaatsen.
Scheiding van Widget en State — een architectuurbeslissing die de onveranderlijkheid van de configuratie waarborgt. Als StatefulWidget zelf de toestand zou opslaan, zou de toestand bij elke herbouw van de ouder verloren gaan. Door de toestand in een apart object onder te brengen, garandeert Flutter dat gegevens herbouw overleven en widgets licht en vergelijkbaar blijven.
Het State-object is geïsoleerd — het heeft geen directe toegang tot de State van andere widgets. Voor gegevensuitwisseling tussen widgets worden InheritedWidget of externe toestandsbeheertools gebruikt: Provider, Riverpod, Bloc, Redux. Elke benadering lost het probleem op zijn eigen manier op: InheritedWidget werkt via de widgetboom, Provider — via een DI-container, Bloc — via gebeurtenisstromen.
De keuze van het hulpmiddel hangt af van de schaal van het project. Voor een kleine applicatie zijn InheritedWidget en lokale State voldoende. Voor een middelgroot en groot project worden Riverpod of Bloc aanbevolen — ze zorgen voor testbaarheid, voorspelbaarheid en scheiding van logica van UI. State wordt daarbij alleen gebruikt voor lokale widgetgegevens (focus, scroll, animatie).
Volgens de Flutter Community Survey 2025 (Flutter Foundation, december 2025) is Riverpod de populairste oplossing voor toestandsbeheer in nieuwe projecten (38%), gevolgd door Bloc (31%) en Provider (22%). Alle drie de tools zijn compatibel met State en vereisen geen afstand van de standaard levenscyclus.
Eerste fout — vergeten te controleren op mounted vóór setState in een asynchrone callback. Wanneer de widget uit de boom is verwijderd (bijv. de gebruiker heeft het scherm verlaten), maar de asynchrone bewerking (HTTP-verzoek) wordt nog uitgevoerd, is State na voltooiing al dood. Het aanroepen van setState in een dode State genereert een uitzondering. De controle if (mounted) setState(...) lost het probleem op.
Tweede fout — initialisatie van InheritedWidget-afhankelijkheden in initState in plaats van didChangeDependencies. In initState is de context nog niet gemonteerd, dus MediaQuery.of(context) genereert een uitzondering. Alle afhankelijkheden van InheritedWidget moeten worden geconfigureerd in didChangeDependencies of in build.
Derde fout — mutatie van velden zonder setState aan te roepen. Als de ontwikkelaar een State-veld wijzigt zonder setState, komt Flutter niet te weten van de wijziging en wordt de UI niet bijgewerkt. Bijvoorbeeld: _list.add(item) zonder daaropvolgend setState((){}) wijzigt de lijst, maar het scherm blijft hetzelfde.
Veiligheidspatroon voor asynchrone bewerkingen in State:
Future<void> _fetchData() async {
final data = await ApiService.fetch();
if (mounted) {
setState(() => _data = data);
}
}
Controle van mounted garandeert dat setState alleen voor een levende State wordt aangeroepen, waardoor de uitzondering „setState called after dispose“ wordt voorkomen.
Veelgestelde vragen
StatefulWidget — de onveranderlijke configuratie van de widget, en State — een veranderlijk object dat gegevens opslaat en de levenscyclus beheert. De widget kan opnieuw worden aangemaakt, State — niet. StatefulWidget maakt State aan via createState.
Precies één. De createState-methode wordt eenmalig aangeroepen bij de eerste inbedding van StatefulWidget in de boom. Zelfs als de ouder meerdere keren herbouwt, blijft het State-object hetzelfde, totdat het type of de Key van de widget verandert.
mounted — een booleaanse vlag die aangeeft of State zich in de widgetboom bevindt. Na het aanroepen van dispose wordt mounted false. Gebruikt voor controle vóór setState in asynchrone callbacks om een uitzondering te voorkomen.
Nee. State is altijd gekoppeld aan een specifieke StatefulWidget via een generiek: State<T extends StatefulWidget>. Het direct aanmaken van State, zonder associatie met een widget, is architectonisch onmogelijk.
Er wordt een uitzondering gegenereerd: „setState called after dispose“. Na het aanroepen van dispose wordt State als dood beschouwd en elke poging om UI via setState te herbouwen is verboden. Oplossing — controleer mounted vóór elke setState.
Samenvatting
We ontwikkelen een mobiele applicatie turnkey
IT Sectr creëert sinds 2017 iOS- en Android-applicaties voor startups en bedrijven. We adviseren u en stellen de beste oplossing voor.
Lees ook