StatefulWidget: wat is het, levenscyclus en werkingsprincipe

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

StatefulWidget — een Flutter-widget met veranderlijke status, waarmee de UI kan reageren op gebruikersacties, asynchrone gebeurtenissen en datastromen. Volgens de officiële Flutter-documentatie (Flutter.dev, 2026) wordt StatefulWidget gebruikt voor alle interactieve elementen van de applicatie: invoerformulieren, animaties, selectievakjes, schakelaars en schermen die gegevens uit het netwerk laden. In tegenstelling tot StatelessWidget maakt het een apart State-object aan dat gedurende de hele levenscyclus behouden blijft en opnieuw kan worden opgebouwd zonder de widget zelf opnieuw aan te maken.

Belangrijkste

  • StatefulWidget — een widget die tijdens het werken zijn status kan wijzigen en de herbouw van de UI via setState kan triggeren
  • Levenscyclus — StatefulWidget doorloopt de fasen createState, initState, didChangeDependencies, build, didUpdateWidget, dispose
  • State-object — een apart object dat de status opslaat en onafhankelijk van de widget bestaat gedurende zijn hele leven
  • setState — de enige legitieme manier om Flutter op de hoogte te stellen van de noodzaak de widget opnieuw op te bouwen na gegevenswijziging
  • Prestaties — overmatig gebruik van StatefulWidget verhoogt het geheugengebruik en de weergavetijd

Wat is StatefulWidget?

StatefulWidget — is een Flutter-klasse die zijn status kan wijzigen als reactie op gebruikersacties, systeemgebeurtenissen of asynchrone bewerkingen. In tegenstelling tot StatelessWidget wordt StatefulWidget niet direct weergegeven — het maakt een State-object aan dat verantwoordelijk is voor de weergave. De opsplitsing in twee klassen (Widget en State) stelt Flutter in staat de UI te herbouwen zonder de widget zelf opnieuw aan te maken, wat een aanzienlijk prestatievoordeel oplevert bij frequente updates.

De architectuur van StatefulWidget volgt het patroon van «scheiding van veranderlijk en onveranderlijk»: de widget zelf blijft onveranderlijk (net als StatelessWidget), terwijl alle veranderlijke status in een apart State-object wordt opgeslagen. Hierdoor kan Flutter widgets hergebruiken door ze te vergelijken op type en Key, terwijl de actuele status tussen herbouwingen behouden blijft.

Volgens Google (Flutter Architectural Overview, 2026) is StatefulWidget optimaal voor scenarioën waarbij de status meer dan eens tijdens de levensduur van de widget verandert: tekstvelden, animaties, timers, datastromen, asynchrone ladingen. Voor eenmalige initialisatie is StatelessWidget voldoende.

Wanneer is StatefulWidget noodzakelijk

StatefulWidget is verplicht wanneer de widget moet reageren op externe gebeurtenissen: het indrukken van een knop, voltooiing van een HTTP-verzoek, gegevensupdate uit de database, abonnement op WebSocket. Het is ook noodzakelijk voor widgets met animatie, tekstvelden met controllers en componenten die de focus beheren. Als de widget alleen gegevens weergeeft en geen gebeurtenissen genereert — gebruik dan StatelessWidget.

Interne structuur

StatefulWidget bestaat uit twee klassen: de eigenlijke StatefulWidget (licht, onveranderlijk) en State (zwaar, veranderlijk). Het framework maakt State aan via de methode createState(), die eenmalig wordt aangeroepen bij het inpassen in de boom. State krijgt een verwijzing naar de widget via de eigenschap widget en kan op elk moment van de levenscyclus de velden ervan benaderen.

Levenscyclus van StatefulWidget

De levenscyclus van StatefulWidget bestaat uit zes hoofdfasen, die elk een overschrijfbare methode bieden voor het uitvoeren van specifieke taken. Inzicht in deze fasen is van cruciaal belang voor correct werken met bronnen en het voorkomen van geheugenlekken.

createState

createState — de eerste methode van de levenscyclus, aangeroepen bij het inpassen van StatefulWidget in de boom. Moet een nieuwe instantie van State retourneren die aan deze widget is gekoppeld. Deze methode wordt precies eenmaal aangeroepen gedurende de hele levensduur van het element. Het is belangrijk hier geen zware bewerkingen uit te voeren — createState moet zo licht mogelijk zijn.

initState

initState — wordt onmiddellijk na het aanmaken van State aangeroepen, vóór de eerste UI-opbouw. Hier worden uitgevoerd: initialisatie van controllers (TextEditingController, AnimationController), abonnement op datastromen (StreamSubscription), instellen van timers en initiële initialisatie van velden. Volgens Flutter-docs (Flutter.dev, 2026) kan BuildContext.of() niet worden aangeroepen in initState — de boom is nog niet volledig gemonteerd.

didChangeDependencies

didChangeDependencies — wordt aangeroepen na initState en elke keer dat de afhankelijkheden van InheritedWidget veranderen. Dit is de juiste plaats om MediaQuery.of(context) aan te roepen of te abonneren op Theme — waarden die tijdens de werking van de app kunnen veranderen. Als de widget InheritedWidget gebruikt, moet de initialisatielogica hier zijn, niet in initState.

build en didUpdateWidget

build — de hoofd-methode die de widgetboom retourneert. Wordt aangeroepen na initState, na didChangeDependencies en na elke setState. didUpdateWidget wordt aangeroepen wanneer de ouder herbouwt en StatefulWidget met nieuwe parameters doorgeeft. Hier kunt u oude en nieuwe widgetvelden vergelijken en indien nodig de status bijwerken.

dispose

dispose — de laatste fase van de levenscyclus. Hier worden alle bronnen vrijgemaakt: uitschrijven van stromen, verwijderen van controllers, annuleren van timers. Het niet aanroepen van dispose leidt tot geheugenlekken. Na dispose wordt State als dood beschouwd — het aanroepen van setState erin genereert een uitzondering.

Hoe werkt StatefulWidget?

Het werkingsmechanisme van StatefulWidget is gebaseerd op het gecoördineerde werk van drie entiteiten: Widget (lichte beschrijving), Element (tussenlaag) en State (gegevensopslag). Wanneer Flutter in de beschrijving een StatefulWidget tegenkomt, maakt het een StatefulElement aan dat createState aanroept en de verwijzing naar het State-object bewaart. Bij herbouw van de ouder vergelijkt Flutter de nieuwe widget met het huidige Element — als het type en Key overeenkomen, wordt het Element bijgewerkt en blijft State hetzelfde.

De status verandert alleen door het aanroepen van setState, dat het framework op de hoogte stelt van de noodzaak tot herbouw. Het is belangrijk te begrijpen: setState verandert de status niet automatisch — het markeert de widget alleen als «vuil». De ontwikkelaar werkt zelf de State-velden bij in de callback die aan setState wordt doorgegeven. Na voltooiing van de callback roept Flutter build aan en werkt de UI bij.

Volgens het Dart/Flutter-team (Dart Language Specification, 2026) garandeert deze scheiding dat alle statuswijzigingen synchroon plaatsvinden vóór de aanroep van build, waardoor de situatie wordt uitgesloten waarin de UI gedeeltelijk bijgewerkte gegevens weergeeft. Dit is het belangrijkste mechanisme voor interfaceconsistentie in Flutter.

Codevoorbeelden in Dart

Laten we een eenvoudige StatefulWidget bekijken — een klikteller voor een knop. Het demonstreert het basismodel: het aanmaken van State, initialisatie van het veld in initState, wijziging via setState:

dart
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('Aantal: $_count'),
        ElevatedButton(
          onPressed: _increment,
          child: const Text('Verhogen'),
        ),
      ],
    );
  }
}

Voorbeeld met asynchroon laden van gegevens en beheer van de levenscyclus. StatefulWidget laadt gegevens uit het netwerk en geeft de laadstatus weer:

dart
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('Hallo, ${_user!.name}');
  }
}

In het tweede voorbeeld is het belangrijk op te merken: initState start een asynchrone bewerking, maar de methode zelf is niet asynchroon. Asynchroniteit wordt gerealiseerd via async/await binnen de aparte methode _loadUser, die de status bijwerkt via setState na voltooiing van het verzoek. Deze aanpak garandeert dat de widget de laadindicator correct weergeeft voordat de gegevens worden ontvangen.

StatefulWidget vs StatelessWidget

De keuze tussen StatefulWidget en StatelessWidget is niet alleen een kwestie van het hebben van status. StatefulWidget biedt een volledige levenscyclus met methoden initState, didChangeDependencies, didUpdateWidget en dispose, wat nodig is voor het werken met controllers, animaties en stromen. StatelessWidget heeft deze methoden niet en is altijd lichter voor het framework.

Aanbeveling van het Flutter-team (Flutter docs, 2026) — minimaliseer het aantal StatefulWidgets in de applicatie door status omhoog te tillen in de boom (State Hoisting) of gebruik te maken van oplossingen voor statusbeheer (Riverpod, Bloc, Provider). Elke StatefulWidget maakt een State-object aan dat leeft tot het verwijderen van het element — hoe meer van dergelijke widgets, hoe hoger de geheugenbelasting.

CriteriumStatefulWidgetStatelessWidget
StatusVeranderlijkOnveranderlijk
Levenscyclus6 fasenAlleen build
State-objectApart aangemaaktNiet vereist
setStateBeschikbaarNiet beschikbaar
AbonnementeninitState/disposeNiet ondersteund
const constructorBeperktVolledig ondersteund
GeheugengebruikHogerLager

Prestaties en optimalisatie

StatefulWidget vereist meer bronnen dan StatelessWidget vanwege de noodzaak een State-object aan te maken en te onderhouden. Echter, correct gebruik van StatefulWidget leidt niet tot prestatieproblemen als een paar regels worden nageleefd. Ten eerste, vermijd diepe nesting van StatefulWidget — elk niveau voegt overhead toe voor het doorlopen van de boom. Ten tweede, splits complexe StatefulWidget op in meerdere eenvoudige widgets, die elk verantwoordelijk zijn voor hun eigen deel van de status.

Volgens Flutter Performance-onderzoek (Flutter.dev, februari 2026) is de meest voorkomende oorzaak van FPS-daling het aanroepen van setState in de bovenliggende widget, die alle nakomelingen herbouwt, inclusief StatelessWidgets die hun weergave niet hebben veranderd. De oplossing — verplaats het veranderlijke deel van de UI naar een aparte StatefulWidget, zodat setState slechts het minimum aan noodzakelijke widgets herbouwt.

Het gebruik van const binnen State is een andere belangrijke techniek. Als onderliggende widgets als const zijn gedeclareerd, zal Flutter ze niet herbouwen bij het aanroepen van setState in de ouder. Dit vermindert de belasting van het framework en verkort de weergavetijd van het frame.

Vermijd frequente setState

Elke aanroep van setState start een volledige herbouw van de widget. Als de status met hoge frequentie verandert (bijvoorbeeld animatie of datastroom), overweeg dan het gebruik van AnimatedBuilder, ValueListenableBuilder of StreamBuilder in plaats van handmatige setState-aanroepen. Deze widgets optimaliseren de herbouw door alleen dat deel van de UI bij te werken dat daadwerkelijk is veranderd.

Veelvoorkomende fouten

De eerste veelvoorkomende fout met StatefulWidget — het aanroepen van setState na dispose. Wanneer de widget uit de boom is verwijderd, wordt State als dood beschouwd en genereert elke setState-aanroep de uitzondering «setState called after dispose». Meestal gebeurt dit wanneer een asynchrone bewerking wordt voltooid na het verwijderen van de widget. De oplossing — controleer de mounted-vlag vóór het aanroepen van setState of annuleer asynchrone bewerkingen in dispose.

De tweede fout — het uitvoeren van zware berekeningen in de build-methode. Aangezien build wordt aangeroepen bij elke setState en bij elke herbouw van de ouder, moeten alle berekeningen zo licht mogelijk zijn. Als u een resource-intensieve bewerking moet uitvoeren — verplaats deze dan naar een aparte Isolate of cache het resultaat in een State-veld.

De derde fout — het niet aanroepen van super.initState() en super.dispose(). Bij het overschrijven van deze methoden is de ontwikkelaar verplicht de ouderimplementatie aan te roepen. Als dit niet gebeurt, kan het framework de status van Element niet correct beheren, wat leidt tot moeilijk vindbare fouten.

Aanbevelingen om fouten te voorkomen

  • Controleer altijd mounted vóór setState in asynchrone callbacks
  • Vergeet niet super.initState() en super.dispose() aan te roepen
  • Doe geen HTTP-verzoeken direct in build — gebruik initState
  • Schrijf u uit voor alle abonnementen in dispose
  • Gebruik een minimaal aantal StatefulWidgets in het project

Veelgestelde vragen

Waarin verschilt StatefulWidget van StatelessWidget?

StatefulWidget kan zijn status wijzigen via setState, heeft een levenscyclus (initState, dispose) en maakt een apart State-object aan. StatelessWidget kan geen status wijzigen en heeft geen levenscyclusmethoden — het geeft alleen doorgegeven gegevens weer.

Hoe vaak wordt createState aangeroepen?

createState wordt precies eenmaal aangeroepen voor elke instantie van StatefulElement. Zelfs als de ouder meerdere keren herbouwt, zolang het type en Key van de widget niet veranderen, wordt createState niet aangeroepen — het bestaande State-object wordt gebruikt.

Wat gebeurt er als dispose niet wordt aangeroepen?

Bronnen worden niet vrijgemaakt: controllers blijven op de achtergrond werken, stroomabonnementen blijven actief, timers worden niet geannuleerd. Dit leidt tot geheugenlekken en kan het aanroepen van setState na dispose veroorzaken, wat een uitzondering genereert.

Kan StatefulWidget const zijn?

Ja, de constructor van StatefulWidget kan const zijn. Dit biedt echter niet hetzelfde voordeel als voor StatelessWidget — het State-object wordt nog steeds aangemaakt bij de eerste inpassing. const heeft alleen invloed op de widget zelf (de lichte wrapper), niet op State.

Waar dient de methode didUpdateWidget voor?

didUpdateWidget wordt aangeroepen wanneer de ouder StatefulWidget met nieuwe parameters doorgeeft. Dit is nodig om de status te synchroniseren met nieuwe gegevens — bijvoorbeeld als userId in de parameters is veranderd, moet het profiel van de nieuwe gebruiker worden geladen.

Samenvatting

  • StatefulWidget — een widget met veranderlijke status die een apart State-object gebruikt voor gegevensopslag en levenscyclusbeheer
  • Levenscyclus bestaat uit createState, initState, didChangeDependencies, build, didUpdateWidget en dispose, elk met een eigen doel
  • setState — de enige legitieme manier om het framework op de hoogte te stellen van statuswijziging, waarna build automatisch wordt aangeroepen
  • mounted — een vlag die moet worden gecontroleerd vóór setState in asynchrone bewerkingen om een uitzondering na dispose te voorkomen
  • Prestaties — StatefulWidget vereist meer bronnen dan StatelessWidget; het wordt aanbevolen het aantal te minimaliseren door status naar externe lagen te verplaatsen
  • const onderliggende widgets binnen State kunnen de omvang van herbouw bij setState verminderen, wat de prestaties verbetert
  • Juiste keuze — gebruik StatefulWidget alleen wanneer de widget veranderlijke gegevens of asynchrone bewerkingen moet beheren

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