StatefulWidget: шта је, животни циклус и принцип рада

Аутор: IT Sectr Објављено: 2026-07-01 Време читања: 9 мин

StatefulWidget — Flutter виџет са променљивим стањем који омогућава UI-ју да реагује на акције корисника, асинхроне догађаје и токове података. Према званичној документацији Flutter-а (Flutter.dev, 2026), StatefulWidget се користи за све интерактивне елементе апликације: обрасце за унос, анимације, поља за потврду, прекидаче и екране који учитавају податке из мреже. За разлику од StatelessWidget-а, он креира засебан објекат State који се чува током целог животног циклуса и може се поново изградити без поновног креирања самог виџета.

Главно

  • StatefulWidget — виџет који може да мења своје стање током рада, покрећући поновну изградњу UI-ја путем setState-а
  • Животни циклус — StatefulWidget пролази кроз фазе createState, initState, didChangeDependencies, build, didUpdateWidget, dispose
  • State објекат — засебан објекат који чува стање и постоји независно од виџета током целог његовог живота
  • setState — једини легитимни начин да се Flutter обавести о потреби поновне изградње виџета након промене података
  • Перформансе — прекомерно коришћење StatefulWidget-а повећава потрошњу меморије и време рендеровања

Шта је StatefulWidget?

StatefulWidget — је Flutter класа која може да мења своје стање као одговор на акције корисника, системске догађаје или асинхроне операције. За разлику од StatelessWidget-а, StatefulWidget се не приказује директно — он креира State објекат који је одговоран за рендеровање. Подела на две класе (Widget и State) омогућава Flutter-у да поново изгради UI без поновног креирања самог виџета, што даје значајну предност у перформансама код честих ажурирања.

Архитектура StatefulWidget-а прати образац «раздвајање променљивог и непроменљивог»: сам виџет остаје непроменљив (као StatelessWidget), а све променљиво стање се чува у засебном State објекту. То омогућава Flutter-у да поново користи виџете упоређујући их по типу и Key-у, и истовремено задржи актуелно стање између поновних изградњи.

Према Google-у (Flutter Architectural Overview, 2026), StatefulWidget је оптималан за сценарије где се стање мења више од једном током живота виџета: текстуална поља, анимације, тајмери, токови података, асинхрона учитавања. За једнократну иницијализацију довољан је StatelessWidget.

Када је StatefulWidget неопходан

StatefulWidget је обавезан када виџет мора да реагује на спољне догађаје: притисак дугмета, завршетак HTTP захтева, ажурирање података из базе, претплата на WebSocket. Такође је неопходан за виџете са анимацијом, текстуална поља са контролерима и компоненте које управљају фокусом. Ако виџет само приказује податке и не генерише догађаје — користите StatelessWidget.

Унутрашња структура

StatefulWidget се састоји од две класе: самог StatefulWidget (лаган, непроменљив) и State (тежак, променљив). Оквир креира State путем метода createState(), који се позива једном приликом уградње у стабло. State добија референцу на виџет преко својства widget и може да приступи његовим пољима у било ком тренутку животног циклуса.

Животни циклус StatefulWidget-а

Животни циклус StatefulWidget-а састоји се од шест главних фаза, од којих свака пружа метод који се може прегазити за извршавање специфичних задатака. Разумевање ових фаза је критично важно за правилан рад са ресурсима и избегавање цурења меморије.

createState

createState — први метод животног циклуса, позива се приликом уградње StatefulWidget-а у стабло. Мора да врати нову инстанцу State-а повезану са овим виџетом. Овај метод се позива тачно једном током целог живота елемента. Важно је не извршавати тешке операције овде — createState мора бити максимално лаган.

initState

initState — позива се одмах након креирања State-а, пре прве изградње UI-ја. Овде се извршава: иницијализација контролера (TextEditingController, AnimationController), претплата на токове података (StreamSubscription), подешавање тајмера и почетна иницијализација поља. Према Flutter документима (Flutter.dev, 2026), у initState-у се не може позвати BuildContext.of() — стабло још није у потпуности монтирано.

didChangeDependencies

didChangeDependencies — позива се након initState-а и сваки пут када се промене зависности InheritedWidget-а. Ово је одговарајуће место за позив MediaQuery.of(context) или претплату на Theme — вредности које се могу променити током рада апликације. Ако виџет користи InheritedWidget, логика иницијализације треба да буде овде, а не у initState-у.

build и didUpdateWidget

build — главни метод који враћа стабло виџета. Позива се након initState-а, након didChangeDependencies-а и након сваког setState-а. didUpdateWidget се позива када родитељ поново изграђује и прослеђује StatefulWidget са новим параметрима. Овде можете упоредити стара и нова поља виџета и, ако је потребно, ажурирати стање.

dispose

dispose — завршна фаза животног циклуса. Овде се ослобађају сви ресурси: отказују претплате на токове, бришу контролери, отказују тајмери. Непозивање dispose-а доводи до цурења меморије. Након dispose-а, State се сматра мртвим — позив setState-а унутар њега баца изузетак.

Како ради StatefulWidget?

Механизам рада StatefulWidget-а заснива се на усклађеном раду три ентитета: Widget (лагани опис), Element (посреднички слој) и State (складиште података). Када Flutter наиђе на StatefulWidget у опису, креира StatefulElement који позива createState и чува референцу на State објекат. При поновној изградњи родитеља, Flutter упоређује нови виџет са тренутним Element-ом — ако се тип и Key поклапају, Element се ажурира, а State остаје исти.

Стање се мења само позивом setState-а, који обавештава оквир о потреби поновне изградње. Важно је разумети: setState не мења стање аутоматски — он само означава виџет као «прљав». Програмер самостално ажурира поља State-а у колбеку прослеђеном setState-у. Након завршетка колбека, Flutter позива build и ажурира UI.

Према Dart/Flutter тиму (Dart Language Specification, 2026), ова подела гарантује да се све промене стања дешавају синхроно пре позива build-а, искључујући ситуацију када UI приказује делимично ажуриране податке. Ово је кључни механизам конзистентности интерфејса у Flutter-у.

Примери кода у Dart-у

Размотримо једноставан StatefulWidget — бројач кликова на дугме. Он демонстрира основни образац: креирање State-а, иницијализацију поља у initState-у, промену путем 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('Број: $_count'),
        ElevatedButton(
          onPressed: _increment,
          child: const Text('Увећај'),
        ),
      ],
    );
  }
}

Пример са асинхроним учитавањем података и управљањем животним циклусом. StatefulWidget учитава податке из мреже и приказује стање учитавања:

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('Здраво, ${_user!.name}');
  }
}

У другом примеру важно је приметити: initState покреће асинхрону операцију, али сам метод није асинхрон. Асинхроност се реализује кроз async/await унутар засебног метода _loadUser, који ажурира стање путем setState-а након завршетка захтева. Овај приступ гарантује да ће виџет исправно приказати индикатор учитавања пре добијања података.

StatefulWidget vs StatelessWidget

Избор између StatefulWidget-а и StatelessWidget-а није само питање постојања стања. StatefulWidget пружа потпуни животни циклус са методима initState, didChangeDependencies, didUpdateWidget и dispose, што је неопходно за рад са контролерима, анимацијама и токовима. StatelessWidget, са своје стране, нема ове методе и увек је лакши за оквир.

Препорука Flutter тима (Flutter docs, 2026) — минимизирати број StatefulWidget-а у апликацији, подизањем стања навише у стаблу (State Hoisting) или коришћењем решења за управљање стањем (Riverpod, Bloc, Provider). Сваки StatefulWidget креира State објекат који живи до уклањања елемента — што је више таквих виџета, веће је оптерећење меморије.

КритеријумStatefulWidgetStatelessWidget
СтањеПроменљивоНепроменљиво
Животни циклус6 фазаСамо build
State објекатКреира се засебноНије потребан
setStateДоступанНије доступан
ПретплатеinitState/disposeНису подржане
const конструкторОграниченПотпуно подржан
Потрошња меморијеВећаМања

Перформансе и оптимизација

StatefulWidget захтева више ресурса од StatelessWidget-а због потребе за креирањем и одржавањем State објекта. Међутим, правилно коришћење StatefulWidget-а не доводи до проблема са перформансама ако се поштује неколико правила. Прво, избегавајте дубоко угњеждавање StatefulWidget-а — сваки ниво додаје додатне трошкове за обилазак стабла. Друго, разбијајте сложене StatefulWidget-е на неколико једноставних, од којих је сваки одговоран за свој део стања.

Према истраживању Flutter Performance (Flutter.dev, фебруар 2026), најчешћи узрок пада FPS-а је позив setState-а у родитељском виџету који поново гради све потомке, укључујући StatelessWidget-е који нису променили свој приказ. Решење — извуците променљиви део UI-ја у засебан StatefulWidget, тако да setState поново гради само минимум потребних виџета.

Коришћење const-а унутар State-а је још једна важна техника. Ако су виџети деце проглашени као const, Flutter их неће поново градити при позиву setState-а у родитељу. Ово смањује оптерећење оквира и смањује време рендеровања кадра.

Избегавајте честе setState

Сваки позив setState-а покреће потпуну поновну изградњу виџета. Ако се стање мења високом фреквенцијом (на пример, анимација или ток података), размотрите коришћење AnimatedBuilder-а, ValueListenableBuilder-а или StreamBuilder-а уместо ручног позива setState-а. Ови виџети оптимизују поновну изградњу, ажурирајући само онај део UI-ја који се стварно променио.

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

Прва типична грешка са StatefulWidget-ом — позив setState-а након dispose-а. Када је виџет уклоњен из стабла, State се сматра мртвим и сваки позив setState-а баца изузетак «setState called after dispose». Најчешће се то дешава када се асинхрона операција заврши након уклањања виџета. Решење — проверавати заставицу mounted пре позива setState-а или отказати асинхроне операције у dispose-у.

Друга грешка — извршавање тешких прорачуна у методи build. Пошто се build позива при сваком setState-у и при свакој поновној изградњи родитеља, сви прорачуни морају бити максимално лагани. Ако је потребно извршити ресурсно захтевну операцију — извуците је у засебан Isolate или кеширајте резултат у пољу State-а.

Трећа грешка — изостанак позива super.initState() и super.dispose(). Прегазећи ове методе, програмер је дужан да позове родитељску имплементацију. Ако се то не уради, оквир неће моћи исправно да управља стањем Element-а, што ће довести до тешко уочљивих грешака.

Препоруке за избегавање грешака

  • Увек проверавај mounted пре setState-а у асинхроним колбецима
  • Не заборави да позовеш super.initState() и super.dispose()
  • Не ради HTTP захтеве директно у build-у — користи initState
  • Откажи све претплате у dispose-у
  • Користи минималан број StatefulWidget-а у пројекту

Често постављана питања

Чиме се StatefulWidget разликује од StatelessWidget-а?

StatefulWidget може да мења своје стање путем setState-а, има животни циклус (initState, dispose) и креира засебан State објекат. StatelessWidget не може да мења стање и нема методе животног циклуса — он само приказује прослеђене податке.

Колико пута се позива createState?

createState се позива тачно једном за сваку инстанцу StatefulElement-а. Чак и ако се родитељ вишеструко поново гради, док се тип и Key виџета не промене, createState се не позива — користи се постојећи State објекат.

Шта ће се десити ако се не позове dispose?

Ресурси се неће ослободити: контролери ће наставити да раде у позадини, претплате на токове ће остати активне, тајмери неће бити отказани. То доводи до цурења меморије и може изазвати позив setState-а након dispose-а, што баца изузетак.

Може ли StatefulWidget бити const?

Да, конструктор StatefulWidget-а може бити const. Међутим, ово не даје исту корист као за StatelessWidget — State објекат ће свеједно бити креиран при првом уграђивању. const утиче само на сам виџет (лаки омотач), не на State.

Чему служи метод didUpdateWidget?

didUpdateWidget се позива када родитељ прослеђује StatefulWidget са новим параметрима. То је потребно да би се стање синхронизовало са новим подацима — на пример, ако се userId у параметрима променио, потребно је учитати профил новог корисника.

Резиме

  • StatefulWidget — виџет са променљивим стањем који користи засебан State објекат за чување података и управљање животним циклусом
  • Животни циклус се састоји од createState, initState, didChangeDependencies, build, didUpdateWidget и dispose, од којих сваки има своју намену
  • setState — једини легитимни начин обавештавања оквира о промени стања, након чега се build аутоматски позива
  • mounted — заставица коју треба проверити пре позива setState-а у асинхроним операцијама ради избегавања изузетка након dispose-а
  • Перформансе — StatefulWidget захтева више ресурса од StatelessWidget-а; препоручује се минимизирање њиховог броја изношењем стања у спољне слојеве
  • const виџети деце унутар State-а омогућавају смањење обима поновне изградње при позиву setState-а, побољшавајући перформансе
  • Правилан избор — користите StatefulWidget само када виџет треба да управља променљивим подацима или асинхроним операцијама

Развићемо мобилну апликацију под кључ

IT Sectr креира iOS и Android апликације за стартапе и предузећа од 2017. године. Саветоваћемо вас и предложити најбоље решење.

Разговарајте о пројекту

Прочитајте такође