StatefulWidget: co to je, životní cyklus a princip fungování

Autor: IT Sectr Publikováno: 2026-07-01 Doba čtení: 9 min

StatefulWidget — widget Flutter s měnitelným stavem, který umožňuje UI reagovat na akce uživatele, asynchronní události a datové toky. Podle oficiální dokumentace Flutter (Flutter.dev, 2026) se StatefulWidget používá pro všechny interaktivní prvky aplikace: vstupní formuláře, animace, zaškrtávací políčka, přepínače a obrazovky načítající data ze sítě. Na rozdíl od StatelessWidget vytváří samostatný objekt State, který je uchováván po celý životní cyklus a může být znovu sestaven bez opětovného vytvoření samotného widgetu.

Hlavní body

  • StatefulWidget — widget, který může během provozu měnit svůj stav a spouštět přestavbu UI pomocí setState
  • Životní cyklus — StatefulWidget prochází fázemi createState, initState, didChangeDependencies, build, didUpdateWidget, dispose
  • Objekt State — samostatný objekt, který ukládá stav a existuje nezávisle na widgetu po celou dobu jeho života
  • setState — jediný legitimní způsob, jak informovat Flutter o nutnosti přestavby widgetu po změně dat
  • Výkon — nadměrné používání StatefulWidget zvyšuje spotřebu paměti a dobu vykreslování

Co je StatefulWidget?

StatefulWidget — je třída Flutter, která může měnit svůj stav v reakci na akce uživatele, systémové události nebo asynchronní operace. Na rozdíl od StatelessWidget není StatefulWidget zobrazen přímo — vytváří objekt State, který je zodpovědný za vykreslování. Rozdělení do dvou tříd (Widget a State) umožňuje Flutter přestavět UI bez opětovného vytvoření samotného widgetu, což přináší významnou výhodu v výkonu při častých aktualizacích.

Architektura StatefulWidget následuje vzor «oddělení měnitelného a neměnného»: samotný widget zůstává neměnný (jako StatelessWidget) a veškerý měnitelný stav je uložen v samostatném objektu State. To umožňuje Flutter znovu používat widgety porovnáváním podle typu a Key a zároveň udržovat aktuální stav mezi přestavbami.

Podle Google (Flutter Architectural Overview, 2026) je StatefulWidget optimální pro scénáře, kde se stav mění více než jednou za životnost widgetu: textová pole, animace, časovače, datové toky, asynchronní načítání. Pro jednorázovou inicializaci stačí StatelessWidget.

Kdy je StatefulWidget nezbytný

StatefulWidget je povinný, když widget musí reagovat na vnější události: stisk tlačítka, dokončení HTTP požadavku, aktualizace dat z databáze, předplatné WebSocket. Je také nezbytný pro widgety s animací, textová pole s ovladači a komponenty spravující fokus. Pokud widget pouze zobrazuje data a negeneruje události — použijte StatelessWidget.

Vnitřní struktura

StatefulWidget se skládá ze dvou tříd: samotného StatefulWidget (lehký, neměnný) a State (těžký, měnitelný). Framework vytváří State pomocí metody createState(), která je volána jednou při vložení do stromu. State získává odkaz na widget prostřednictvím vlastnosti widget a může přistupovat k jeho polím kdykoli během životního cyklu.

Životní cyklus StatefulWidget

Životní cyklus StatefulWidget se skládá ze šesti hlavních fází, z nichž každá poskytuje přepisovatelnou metodu pro provádění specifických úkolů. Pochopení těchto fází je kriticky důležité pro správnou práci se zdroji a předcházení únikům paměti.

createState

createState — první metoda životního cyklu, volaná při vložení StatefulWidget do stromu. Musí vrátit novou instanci State spojenou s tímto widgetem. Tato metoda je volána přesně jednou za celou dobu života prvku. Je důležité zde neprovádět těžké operace — createState by měl být co nejlehčí.

initState

initState — je volán ihned po vytvoření State, před první stavbou UI. Zde se provádí: inicializace ovladačů (TextEditingController, AnimationController), předplatné datových toků (StreamSubscription), nastavení časovačů a počáteční inicializace polí. Podle Flutter docs (Flutter.dev, 2026) nelze v initState volat BuildContext.of() — strom ještě není plně připojen.

didChangeDependencies

didChangeDependencies — je volán po initState a pokaždé, když se změní závislosti InheritedWidget. Toto je vhodné místo pro volání MediaQuery.of(context) nebo předplatné Theme — hodnoty, které se mohou změnit během běhu aplikace. Pokud widget používá InheritedWidget, logika inicializace by měla být zde, ne v initState.

build a didUpdateWidget

build — hlavní metoda vracející strom widgetů. Volána po initState, po didChangeDependencies a po každém setState. didUpdateWidget je volán, když rodič přestavuje a předává StatefulWidget s novými parametry. Zde můžete porovnat stará a nová pole widgetu a v případě potřeby aktualizovat stav.

dispose

dispose — závěrečná fáze životního cyklu. Zde jsou uvolněny všechny zdroje: odhlášení z toků, odstranění ovladačů, zrušení časovačů. Nevolání dispose vede k únikům paměti. Po dispose je State považován za mrtvý — volání setState uvnitř něj vyvolá výjimku.

Jak funguje StatefulWidget?

Mechanismus fungování StatefulWidget je založen na koordinované práci tří entit: Widget (lehký popis), Element (mezivrstva) a State (úložiště dat). Když Flutter narazí na StatefulWidget v popisu, vytvoří StatefulElement, který volá createState a ukládá odkaz na objekt State. Při přestavbě rodiče Flutter porovnává nový widget s aktuálním Elementem — pokud se typ a Key shodují, Element je aktualizován a State zůstává stejný.

Stav se mění pouze voláním setState, které informuje framework o nutnosti přestavby. Je důležité pochopit: setState nemění stav automaticky — pouze označí widget jako «špinavý». Vývojář sám aktualizuje pole State v callbacku předaném setState. Po dokončení callbacku Flutter zavolá build a aktualizuje UI.

Podle týmu Dart/Flutter (Dart Language Specification, 2026) toto oddělení zaručuje, že všechny změny stavu probíhají synchronně před voláním build, což vylučuje situaci, kdy UI zobrazuje částečně aktualizovaná data. To je klíčový mechanismus konzistence rozhraní ve Flutter.

Příklady kódu v Dart

Podívejme se na jednoduchý StatefulWidget — počítadlo kliknutí na tlačítko. Ukazuje základní vzor: vytvoření State, inicializace pole v initState, změna prostřednictvím 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('Počet: $_count'),
        ElevatedButton(
          onPressed: _increment,
          child: const Text('Zvýšit'),
        ),
      ],
    );
  }
}

Příklad s asynchronním načítáním dat a správou životního cyklu. StatefulWidget načítá data ze sítě a zobrazuje stav načítání:

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

Ve druhém příkladu je důležité poznamenat: initState spouští asynchronní operaci, ale samotná metoda není asynchronní. Asynchronnost je realizována pomocí async/await uvnitř samostatné metody _loadUser, která aktualizuje stav pomocí setState po dokončení požadavku. Tento přístup zaručuje, že widget správně zobrazí indikátor načítání před obdržením dat.

StatefulWidget vs StatelessWidget

Volba mezi StatefulWidget a StatelessWidget není jen otázkou existence stavu. StatefulWidget poskytuje plný životní cyklus s metodami initState, didChangeDependencies, didUpdateWidget a dispose, což je nezbytné pro práci s ovladači, animacemi a toky. StatelessWidget naproti tomu tyto metody nemá a je vždy lehčí pro framework.

Doporučení týmu Flutter (Flutter docs, 2026) — minimalizujte počet StatefulWidget v aplikaci zvedáním stavu nahoru ve stromu (State Hoisting) nebo pomocí řešení pro správu stavu (Riverpod, Bloc, Provider). Každý StatefulWidget vytváří objekt State, který žije až do odstranění prvku — čím více takových widgetů, tím vyšší je zatížení paměti.

KritériumStatefulWidgetStatelessWidget
StavMěnitelnýNeměnný
Životní cyklus6 fázíPouze build
Objekt StateVytvářen samostatněNení vyžadován
setStateDostupnýNedostupný
PředplatnáinitState/disposeNejsou podporována
const konstruktorOmezenýPlně podporován
Spotřeba pamětiVyššíNižší

Výkon a optimalizace

StatefulWidget vyžaduje více zdrojů než StatelessWidget kvůli potřebě vytvářet a udržovat objekt State. Správné používání StatefulWidget však nevede k problémům s výkonem, pokud se dodržuje několik pravidel. Za prvé, vyhněte se hlubokému vnoření StatefulWidget — každá úroveň přidává režii pro procházení stromu. Za druhé, rozdělte složitý StatefulWidget na několik jednoduchých widgetů, z nichž každý je zodpovědný za svou část stavu.

Podle výzkumu Flutter Performance (Flutter.dev, únor 2026) je nejčastější příčinou poklesu FPS volání setState v nadřazeném widgetu, které přestavuje všechny potomky, včetně StatelessWidget, které nezměnily své zobrazení. Řešením je přesunout měnitelnou část UI do samostatného StatefulWidget, aby setState přestavěl pouze minimum potřebných widgetů.

Použití const uvnitř State je další důležitá technika. Pokud jsou podřízené widgety deklarovány jako const, Flutter je nebude přestavovat při volání setState v rodiči. To snižuje zatížení frameworku a zkracuje dobu vykreslování snímku.

Vyhněte se častým setState

Každé volání setState spouští úplnou přestavbu widgetu. Pokud se stav mění s vysokou frekvencí (například animace nebo datový tok), zvažte použití AnimatedBuilder, ValueListenableBuilder nebo StreamBuilder místo ručního volání setState. Tyto widgety optimalizují přestavbu a aktualizují pouze tu část UI, která se skutečně změnila.

Typické chyby

První typická chyba se StatefulWidget — volání setState po dispose. Když je widget odstraněn ze stromu, State je považován za mrtvý a každé volání setState vyvolá výjimku «setState called after dispose». Nejčastěji k tomu dochází, když asynchronní operace skončí po odstranění widgetu. Řešením je kontrola příznaku mounted před voláním setState nebo zrušení asynchronních operací v dispose.

Druhou chybou je provádění těžkých výpočtů v metodě build. Protože build je volán při každém setState a při každé přestavbě rodiče, všechny výpočty by měly být co nejlehčí. Pokud potřebujete provést operaci náročnou na zdroje — přesuňte ji do samostatného Isolate nebo uložte výsledek do pole State.

Třetí chybou je chybějící volání super.initState() a super.dispose(). Při přepisování těchto metod je vývojář povinen zavolat rodičovskou implementaci. Pokud se tak nestane, framework nebude schopen správně spravovat stav Element, což povede k obtížně odhalitelným chybám.

Doporučení pro předcházení chybám

  • Vždy kontrolujte mounted před setState v asynchronních callback
  • Nezapomeňte volat super.initState() a super.dispose()
  • Neprovádějte HTTP požadavky přímo v build — použijte initState
  • Zrušte všechna předplatná v dispose
  • Používejte minimální počet StatefulWidget v projektu

Často kladené otázky

Čím se StatefulWidget liší od StatelessWidget?

StatefulWidget může měnit svůj stav prostřednictvím setState, má životní cyklus (initState, dispose) a vytváří samostatný objekt State. StatelessWidget nemůže měnit stav a nemá metody životního cyklu — pouze zobrazuje předaná data.

Kolikrát je voláno createState?

createState je voláno přesně jednou pro každou instanci StatefulElement. I když rodič opakovaně přestavuje, dokud se typ a Key widgetu nemění, createState není voláno — používá se existující objekt State.

Co se stane, když není zavoláno dispose?

Zdroje se neuvolní: ovladače budou nadále pracovat na pozadí, předplatná toků zůstanou aktivní, časovače nebudou zrušeny. To vede k únikům paměti a může způsobit volání setState po dispose, což vyvolá výjimku.

Může být StatefulWidget const?

Ano, konstruktor StatefulWidget může být const. Nepřináší to však stejnou výhodu jako pro StatelessWidget — objekt State bude stejně vytvořen při prvním vložení. const ovlivňuje pouze samotný widget (lehký obal), ne State.

K čemu slouží metoda didUpdateWidget?

didUpdateWidget je volán, když rodič předává StatefulWidget s novými parametry. To je potřeba k synchronizaci stavu s novými daty — například pokud se změnilo userId v parametrech, je třeba načíst profil nového uživatele.

Shrnutí

  • StatefulWidget — widget s měnitelným stavem, který používá samostatný objekt State pro ukládání dat a správu životního cyklu
  • Životní cyklus se skládá z createState, initState, didChangeDependencies, build, didUpdateWidget a dispose, každý má svůj účel
  • setState — jediný legitimní způsob informování frameworku o změně stavu, po kterém je build automaticky volán
  • mounted — příznak, který je třeba zkontrolovat před setState v asynchronních operacích, aby se předešlo výjimce po dispose
  • Výkon — StatefulWidget vyžaduje více zdrojů než StatelessWidget; doporučuje se minimalizovat jejich počet přesunem stavu do vnějších vrstev
  • const podřízené widgety uvnitř State umožňují snížit objem přestavby při volání setState, čímž zlepšují výkon
  • Správná volba — používejte StatefulWidget pouze tehdy, když widget potřebuje spravovat měnitelná data nebo asynchronní operace

Vyvineme mobilní aplikaci na klíč

IT Sectr vytváří aplikace pro iOS a Android pro startupy a podniky od roku 2017. Poradíme vám a navrhneme nejlepší řešení.

Prodiskutovat projekt

Přečtěte si také