State: wat is het, toestandsbeheer en werkingsprincipe

Auteur: IT Sectr Gepubliceerd: 2026-07-01 Leestijd: 9 min

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 — object dat wijzigbare gegevens van StatefulWidget opslaat en de herbouw ervan beheert via setState
  • Levenscyclus — State doorloopt initState, didChangeDependencies, build, didUpdateWidget en dispose, elke fase met een duidelijke functie
  • mounted — vlag die aangeeft dat State zich nog in de widgetboom bevindt en veilig setState kan aanroepen
  • widget — verwijzing naar de gekoppelde StatefulWidget, toegankelijk via de eigenschap State om de parameters van de ouder te lezen
  • Isolatie — State is geïsoleerd van andere States; voor gegevensuitwisseling worden InheritedWidget of externe toestandsbeheertools gebruikt

Wat is State in Flutter?

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.

Waar wordt State opgeslagen?

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.

Levenscyclus van State

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 — initialisatie

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

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 — UI bouwen

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

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 — bronnen vrijgeven

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.

MethodeWanneer aangeroepenVerplichte super
initStateBij het aanmaken van StateJa, in de eerste regel
didChangeDependenciesNa initState en bij wijziging van InheritedWidgetJa
buildNa initState, didChangeDependencies, setStateNee
didUpdateWidgetBij nieuwe widget van de ouderJa
setStateBij aanroep door de ontwikkelaarNee
disposeBij verwijdering uit de boomJa, in de laatste regel

Hoe werkt State?

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.

Codevoorbeelden in Dart

Basisvoorbeeld van State met een veld dat door een timer wordt gewijzigd. Demonstreert initState, setState en dispose:

dart
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:

dart
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 vs StatefulWidget

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.

Waarom kan StatefulWidget geen State zijn?

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.

Toestandsbeheer tussen widgets

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.

Lokale vs globale toestand

  • Lokale toestand — in de State van een specifieke widget (scrollpositie, focustoestand)
  • Globale toestand — in externe opslag (gebruikersgegevens, instellingen, cache)
  • Regel: als gegevens door slechts één widget worden gebruikt — bewaar in State
  • Als gegevens door 2+ widgets worden gebruikt — verplaats naar Riverpod/Bloc/Provider

Veelgemaakte fouten

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.

Controle van mounted vóór setState

Veiligheidspatroon voor asynchrone bewerkingen in State:

dart
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

Waarin verschilt State van StatefulWidget?

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.

Hoeveel State-objecten worden er voor één StatefulWidget aangemaakt?

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.

Wat is mounted in State?

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.

Kan State zonder StatefulWidget worden gebruikt?

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.

Wat gebeurt er als setState in dispose wordt aangeroepen?

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

  • State — gegevensbeheerobject van StatefulWidget, slaat wijzigbare velden op en initieert UI-herbouw via setState
  • Levenscyclus omvat de verplichte methoden initState, didChangeDependencies, build, didUpdateWidget en dispose, elk met een eigen doel
  • mounted — kritieke veiligheidsvlag die het aanroepen van setState na verwijdering van de widget uit de boom voorkomt
  • widget — de eigenschap van State voor toegang tot parameters van de gekoppelde StatefulWidget, bijgewerkt via didUpdateWidget
  • Isolatie — State heeft geen toegang tot andere States; interactie tussen widgets vindt plaats via InheritedWidget of externe tools
  • setState — roept build niet onmiddellijk aan, maar markeert State alleen als vuil voor herbouw in het volgende frame
  • Regel — gebruik State voor lokale widgetgegevens; verplaats globale toestand naar externe lagen (Riverpod, Bloc)

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.

Bespreek het project

Lees ook