State: какво е това, управление на състоянието и принцип на работа

Автор: IT Sectr Публикувано: 2026-07-01 Време за четене: 9 мин

State — централният обект за управление на данни във Flutter, асоцииран с StatefulWidget и отговорен за съхранение на променяща се информация и изграждане на интерфейса. Според официалната документация на Flutter (Flutter.dev, 2026), State съществува през целия жизнен цикъл на widget и преживява неговото преизграждане, осигурявайки консистентност на данните между актуализациите на UI. За разлика от самия widget, State може да променя своите полета и да инициира преизграждане чрез извикване на setState.

Основни неща

  • State — обект, съхраняващ променливи данни на StatefulWidget и управляващ неговото преизграждане чрез setState
  • Жизнен цикъл — State преминава през initState, didChangeDependencies, build, didUpdateWidget и dispose, всеки етап с ясно предназначение
  • mounted — флаг, указващ че State все още е в дървото на widget и може безопасно да извиква setState
  • widget — препратка към свързания StatefulWidget, достъпна чрез свойството State за четене на параметри на родителя
  • Изолация — State е изолиран от други State; за обмен на данни се използват InheritedWidget или външни инструменти за управление на състоянието

Какво е State във Flutter?

State — това е обект в архитектурата на Flutter, който съхранява променливи данни на StatefulWidget и определя как тези данни се показват в интерфейса. Всеки StatefulWidget при вграждане в дървото създава точно един обект State чрез метода createState. State съществува независимо от widget: ако родителят преизгради StatefulWidget с нови параметри, State остава същият и получава актуализирания widget чрез свойството widget.

Според Flutter Architectural Overview (Google, 2026), разделянето на Widget и State е съзнателно архитектурно решение, позволяващо на framework-а да преизползва елементи на дървото. Widget (леко описание) може да бъде създаван и унищожаван многократно, но State (тежък обект с данни) остава в паметта, докато елементът е в дървото. Това предотвратява загуба на данни при чести преизграждания на родителски widget.

State имплементира интерфейса StatefulWidget чрез generics: class _MyState extends State<MyWidget>. Generic-ът свързва State с конкретен тип StatefulWidget, осигурявайки type-safe достъп до неговите полета чрез свойството widget.

Къде се съхранява State?

Обектът State се съхранява в StatefulElement — междинния слой между Widget и RenderObject. StatefulElement създава State чрез createState, запазва препратка към него и предава State като собственик. Element се унищожава само когато widget бъде премахнат от дървото — до този момент State живее в паметта.

Жизнен цикъл на State

Жизненият цикъл на State е детерминиран и се състои от строга последователност от извиквания. Разбирането на тази последователност е основа за коректна работа с ресурси и предотвратяване на изтичане на памет.

initState — инициализация

initState се извиква първи при създаване на State. В този метод се инициализират контролери, абонаменти за потоци от данни, таймери и начални стойности на полета. Задължително е извикването на super.initState() в първия ред. На етапа initState дървото на widget все още не е напълно монтирано, затова методи като MediaQuery.of(context) може да работят некоректно.

didChangeDependencies

didChangeDependencies се извиква след initState и при всяка промяна на InheritedWidget зависимости. Именно тук, а не в initState, трябва да се извиква MediaQuery.of(context) или Theme.of(context), тъй като към този момент дървото вече е монтирано. Този метод също се извиква ако widget бъде преместен в друг контекст, където InheritedWidget предоставя различни стойности.

build — изграждане на UI

build е основният метод на State, връщащ дървото на widget. Извиква се след initState, след didChangeDependencies и след всяко setState. Методът build не трябва да има странични ефекти — той само описва интерфейса на базата на текущите стойности на полетата на State.

didUpdateWidget

didUpdateWidget се извиква когато родителят преизгради StatefulWidget с нови параметри. State получава достъп до стария widget чрез oldWidget и може да го сравни с новия. Ако параметрите са се променили, може да актуализира състоянието, да зареди нови данни или да рестартира анимация.

dispose — освобождаване на ресурси

dispose е заключителният метод, в който се освобождават всички ресурси: контролери, абонаменти, таймери. След dispose State се маркира като мъртъв: mounted връща false, извикването на setState хвърля изключение. Задължително е извикването на super.dispose() в последния ред на метода.

МетодКога се извикваЗадължително super
initStateПри създаване на StateДа, в първия ред
didChangeDependenciesСлед initState и при промяна на InheritedWidgetДа
buildСлед initState, didChangeDependencies, setStateНе
didUpdateWidgetПри нов widget от родителяДа
setStateПо извикване от разработчикаНе
disposeПри премахване от дървотоДа, в последния ред

Как работи State?

Механизмът на работа на State се основава на три ключови принципа: асоциация с Element, реактивност чрез setState и достъп до родителя чрез свойството widget. Когато Flutter изгражда дървото от елементи и срещне StatefulElement, той извиква createState на свързания widget. Създаденият State се съхранява в елемента и съществува докато елементът не бъде премахнат.

При извикване на setState, State се маркира като „мръсен" (dirty) и планира преизграждане за следващия кадър. Важно: setState не извиква build веднага — той само регистрира необходимостта от преизграждане. Flutter събира всички dirty-елементи за текущия кадър и ги преизгражда пакетно, което оптимизира производителността. След извикване на build State се връща в състояние „чист" (clean).

Свойството widget позволява на State да чете параметри, предадени на конструктора на StatefulWidget. Тъй като StatefulWidget е неизменяем (като StatelessWidget), неговите полета не се променят — при промяна на параметрите родителят създава нов widget, а State го получава чрез didUpdateWidget. Това гарантира, че State винаги работи с актуални данни от родителя.

Примерен код на Dart

Основен пример на State с поле, променяно по таймер. Демонстрира initState, setState и 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(' секунди изминаха');
  }
}

Пример с използване на свойството widget за достъп до параметри на родителя и реагиране на техните промени чрез 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('Здравейте, !');
  }
}

Във втория пример State проследява промяната на входния параметър name и преформатира показването само при реална промяна. Без проверката widget.name != oldWidget.name методът би се извиквал при всяко преизграждане на родителя, дори ако името не се е променило — това е излишна работа за framework-а.

State срещу StatefulWidget

State и StatefulWidget са два различни класа в архитектурата на Flutter, изпълняващи различни роли. StatefulWidget е лека неизменяема обвивка, която описва конфигурацията на widget и създава State. State е тежък обект, който съхранява променливи данни, управлява абонаменти и изгражда UI. Такова разделение позволява на Flutter да унищожава и създава widget без загуба на състояние.

Всички полета на StatefulWidget трябва да бъдат final и да се задават в конструктора — те не се променят след създаване. State, напротив, може да променя своите полета по всяко време, но всички промени трябва да бъдат предшествани от извикване на setState, за да може Flutter да разбере за необходимостта от преизграждане. Това е ключовата разлика: StatefulWidget — „какво да покажа", State — „как да го покажа и какви данни да използвам".

Според анализа на изходния код на Flutter (Flutter SDK, 2026), StatefulWidget съдържа само едно задължително поле — createState, докато State има достъп до BuildContext, може да се абонира за потоци, да управлява анимации и контролери. Препоръчително е да се държи StatefulWidget максимално прост, прехвърляйки цялата логика в State.

Защо StatefulWidget не може да бъде State?

Разделението на Widget и State е архитектурно решение, осигуряващо неизменяемост на конфигурацията. Ако StatefulWidget сам съхраняваше състоянието, при всяко преизграждане на родителя състоянието би се загубило. Изнасяйки състоянието в отделен обект, Flutter гарантира, че данните преживяват преизграждания, а widget остават леки и сравними.

Управление на състоянието между widget

Обектът State е изолиран — той няма пряк достъп до State на други widget. За обмен на данни между widget се използват InheritedWidget или външни инструменти за управление на състоянието: Provider, Riverpod, Bloc, Redux. Всеки подход решава задачата по различен начин: InheritedWidget работи чрез дървото на widget, Provider — чрез DI-контейнер, Bloc — чрез потоци от събития.

Изборът на инструмент зависи от мащаба на проекта. За малко приложение са достатъчни InheritedWidget и локално State. За среден и голям проект се препоръчва Riverpod или Bloc — те осигуряват тестируемост, предсказуемост и отделяне на логиката от UI. State при това се използва само за локални данни на widget (фокус, скрол, анимация).

Според Flutter Community Survey 2025 (Flutter Foundation, декември 2025), Riverpod е най-популярното решение за управление на състоянието в нови проекти (38%), следвано от Bloc (31%) и Provider (22%). И трите инструмента са съвместими със State и не изискват отказ от стандартния жизнен цикъл.

Локално срещу глобално състояние

  • Локално състояние — в State на конкретен widget (позиция на скрол, състояние на фокус)
  • Глобално състояние — във външно хранилище (данни на потребителя, настройки, кеш)
  • Правило: ако данните се използват само от един widget — съхранявайте в State
  • Ако данните се използват от 2+ widget — изнесете в Riverpod/Bloc/Provider

Типични грешки

Първа грешка — да забравите да проверите mounted преди setState в асинхронен callback. Когато widget е премахнат от дървото (напр. потребителят е напуснал екрана), но асинхронната операция (HTTP заявка) все още се изпълнява, след нейното завършване State вече е мъртъв. Извикването на setState в мъртъв State хвърля изключение. Проверката if (mounted) setState(...) решава проблема.

Втора грешка — инициализация на InheritedWidget зависимости в initState вместо в didChangeDependencies. В initState контекстът все още не е монтиран, затова MediaQuery.of(context) ще хвърли изключение. Всички зависимости от InheritedWidget трябва да се настройват в didChangeDependencies или в build.

Трета грешка — мутация на полета без извикване на setState. Ако разработчикът променя поле на State без setState, Flutter няма да разбере за промяната и UI няма да се актуализира. Например: _list.add(item) без последващо setState((){}) ще промени списъка, но екранът ще остане същият.

Проверка на mounted преди setState

Модел за безопасност за асинхронни операции в State:

dart
Future<void> _fetchData() async {
  final data = await ApiService.fetch();
  if (mounted) {
    setState(() => _data = data);
  }
}

Проверката на mounted гарантира, че setState се извиква само за жив State, предотвратявайки изключението „setState called after dispose".

Често задавани въпроси

Каква е разликата между State и StatefulWidget?

StatefulWidget — неизменяема конфигурация на widget, а State — променящ се обект, съхраняващ данни и управляващ жизнения цикъл. Widget може да бъде пресъздаден, State — не. StatefulWidget създава State чрез createState.

Колко обекта State се създават за един StatefulWidget?

Точно един. Методът createState се извиква еднократно при първото вграждане на StatefulWidget в дървото. Дори ако родителят се преизгражда многократно, обектът State остава същият, докато не се промени типът или Key на widget.

Какво е mounted в State?

mounted — булев флаг, показващ дали State е в дървото на widget. След извикване на dispose mounted става false. Използва се за проверка преди setState в асинхронни callback-и, за да се избегне изключение.

Може ли да се използва State без StatefulWidget?

Не. State винаги е свързан с конкретен StatefulWidget чрез generic: State<T extends StatefulWidget>. Да се създаде State директно, без асоциация с widget, е архитектурно невъзможно.

Какво се случва при извикване на setState в dispose?

Ще се хвърли изключение „setState called after dispose". След извикване на dispose State се счита за мъртъв и всякакви опити за преизграждане на UI чрез setState са забранени. Решението — проверявайте mounted преди всяко setState.

Резюме

  • State — обект за управление на данни на StatefulWidget, съхраняващ променливи полета и иницииращ преизграждане на UI чрез setState
  • Жизнен цикъл включва задължителните методи initState, didChangeDependencies, build, didUpdateWidget и dispose, всеки със своето предназначение
  • mounted — критичен флаг за безопасност, предотвратяващ извикване на setState след премахване на widget от дървото
  • widget — свойство на State за достъп до параметри на свързания StatefulWidget, актуализирано чрез didUpdateWidget
  • Изолация — State няма достъп до други State; междуwidget комуникацията се реализира чрез InheritedWidget или външни инструменти
  • setState — не извиква build веднага, а само маркира State като мръсен за преизграждане в следващия кадър
  • Правило — използвайте State за локални данни на widget; глобалното състояние изнасяйте във външни слоеве (Riverpod, Bloc)

Ще разработим мобилно приложение под ключ

IT Sectr създава iOS и Android приложения за стартъпи и бизнеси от 2017 г. Ще ви консултираме и ще предложим най-доброто решение.

Обсъдете проекта

Прочетете също