State — централни објекат управљања подацима у Flutter-у, повезан са StatefulWidget-ом и одговоран за чување променљивих информација и изградњу интерфејса. Према званичној документацији Flutter-а (Flutter.dev, 2026), State постоји током целог животног циклуса виџета и преживљава његова престројавања, обезбеђујући конзистентност података између ажурирања UI. За разлику од самог виџета, State може да мења своја поља и покреће престројавање кроз позив setState.
Главно
State — је објекат у архитектури Flutter-а који чува променљиве податке StatefulWidget-а и одређује како се ти подаци приказују у интерфејсу. Сваки StatefulWidget при уграђивању у стабло ствара тачно један објекат State кроз метод createState. State постоји независно од виџета: ако родитељ престројава StatefulWidget са новим параметрима, State остаје исти и прима ажурирани виџет кроз својство widget.
Према Flutter Architectural Overview (Google, 2026), раздвајање Widget и State је свесна архитектонска одлука која омогућава фрејмворку да поново користи елементе стабла. Виџет (лак опис) може бити креиран и уништен више пута, али State (тежак објекат са подацима) остаје у меморији док год се елемент налази у стаблу. Ово спречава губитак података при честим престројавањима родитељских виџета.
State имплементира интерфејс StatefulWidget кроз генерик: class _MyState extends State<MyWidget>. Генерик повезује State са одређеним типом StatefulWidget-а, обезбеђујући типно безбедан приступ његовим пољима кроз својство widget.
Објекат State се чува у StatefulElement-у — међуслоју између Widget-а и RenderObject-а. StatefulElement ствара State кроз createState, чува референцу на њега и прослеђује State као власника. Element се уништава тек када се виџет уклони из стабла — до тада State живи у меморији.
Животни циклус State-а је детерминистички и састоји се од строгог низа позива. Разумевање овог низа је основа исправног рада са ресурсима и спречавања цурења меморије.
initState се позива први приликом креирања State-а. У овом методу се иницијализују контролери, претплате на токове података, тајмери и почетне вредности поља. Обавезно је позивање super.initState() у првом реду. У фази initState стабло виџета још није у потпуности монтирано, па методе попут MediaQuery.of(context) могу радити неисправно.
didChangeDependencies се позива након initState и при свакој промени InheritedWidget зависности. Управо овде, а не у initState, треба позивати MediaQuery.of(context) или Theme.of(context), јер је у овом тренутку стабло већ монтирано. Овај метод се такође позива ако се виџет премести у други контекст где InheritedWidget пружа другачије вредности.
build — главни метод State-а који враћа стабло виџета. Позива се након initState, након didChangeDependencies и након сваког setState. Метод build не сме имати споредне ефекте — он само описује интерфејс на основу текућих вредности поља State-а.
didUpdateWidget се позива када родитељ престројава StatefulWidget са новим параметрима. State добија приступ старом виџету кроз oldWidget и може да га упореди са новим. Ако су се параметри променили, може се ажурирати стање, учитати нови подаци или поново покренути анимација.
dispose — завршни метод у коме се ослобађају сви ресурси: контролери, претплате, тајмери. Након dispose, State се означава као мртав: mounted враћа false, позив setState баца изузетак. Обавезно је позивање super.dispose() у последњем реду метода.
| Метод | Када се позива | Обавезни super |
|---|---|---|
| initState | При креирању State-а | Да, у првом реду |
| didChangeDependencies | Након initState и при промени InheritedWidget | Да |
| build | Након initState, didChangeDependencies, setState | Не |
| didUpdateWidget | При новом виџету од родитеља | Да |
| setState | По позиву програмера | Не |
| dispose | При уклањању из стабла | Да, у последњем реду |
Механизам рада State-а заснива се на три кључна принципа: асоцијација са Element-ом, реактивност кроз setState и приступ родитељу кроз својство widget. Када Flutter гради стабло елемената и наиђе на StatefulElement, позива createState повезаног виџета. Креирани State се чува у елементу и постоји док се елемент не уклони.
При позиву setState, State означава себе као „прљав„ (dirty) и планира престројавање за следећи кадар. Важно: setState не позива build одмах — он само региструје потребу за престројавањем. Flutter прикупља све прљаве елементе у текућем кадру и престројава их групно, што оптимизује перформансе. Након позива build, State се враћа у стање „чист„ (clean).
Својство widget омогућава State-у да чита параметре прослеђене конструктору StatefulWidget-а. Пошто је StatefulWidget непроменљив (као StatelessWidget), његова поља се не мењају — при промени параметара родитељ ствара нови виџет, а State га прима кроз didUpdateWidget. Ово гарантује да State увек ради са актуелним подацима родитеља.
Основни пример State-а са пољем које мења тајмер. Демонстрира initState, setState и dispose:
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 секунди је прошло');
}
}
Пример коришћења својства widget за приступ параметрима родитеља и реаговање на њихове промене кроз didUpdateWidget:
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('Здраво, $_displayName!');
}
}
У другом примеру State прати промену улазног параметра name и преформатира приказ само при стварној промени. Без провере widget.name != oldWidget.name, метод би се позивао при сваком престројавању родитеља, чак и ако се име није променило — то је непотребан рад за фрејмворк.
State и StatefulWidget су два различита класа у архитектури Flutter-а са различитим улогама. StatefulWidget — је лаки непроменљиви омотач који описује конфигурацију виџета и ствара State. State — је тешки објекат који чува променљиве податке, управља претплатама и гради UI. Ово раздвајање омогућава Flutter-у да уништава и ствара виџете без губитка стања.
Сва поља StatefulWidget-а морају бити final и постављена у конструктору — она се не мењају након креирања. State, напротив, може да мења своја поља у било ком тренутку, али све промене морају бити попраћене позивом setState, како би Flutter сазнао за потребу престројавања. Ово је кључна разлика: StatefulWidget је „шта показати„, State — „како показати и које податке користити„.
Према Flutter source code analysis (Flutter SDK, 2026), StatefulWidget садржи само једно обавезно поље — createState, док State има приступ BuildContext-у, може да се претплати на токове, управља анимацијама и контролерима. Препоручује се да StatefulWidget буде што једноставнији, преносећи сву логику у State.
Раздвајање Widget и State — архитектонска одлука која обезбеђује непроменљивост конфигурације. Ако би StatefulWidget сам чувао стање, при сваком престројавању родитеља стање би се губило. Издвајањем стања у засебан објекат, Flutter гарантује да подаци преживљавају престројавања, а виџети остају лаки и упоредиви.
Објекат State је изолован — нема директан приступ State-у других виџета. За размену података између виџета користе се InheritedWidget или спољни алати за управљање стањем: Provider, Riverpod, Bloc, Redux. Сваки приступ решава задатак на свој начин: InheritedWidget ради кроз стабло виџета, Provider — кроз DI контејнер, Bloc — кроз токове догађаја.
Избор алата зависи од обима пројекта. За малу апликацију довољни су InheritedWidget и локални State. За средњи и велики пројекат препоручују се Riverpod или Bloc — они обезбеђују тестирабилност, предвидљивост и одвајање логике од UI. State се притом користи само за локалне податке виџета (фокус, скрол, анимација).
Према Flutter Community Survey 2025 (Flutter Foundation, децембар 2025), Riverpod је најпопуларније решење за управљање стањем у новим пројектима (38%), следе га Bloc (31%) и Provider (22%). Сва три алата су компатибилна са State-ом и не захтевају одустајање од стандардног животног циклуса.
Прва грешка — заборавити да проверите mounted пре setState у асинхроном колбеку. Када је виџет уклоњен из стабла (нпр. корисник је напустио екран), али асинхрона операција (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((){}) ће променити листу, али екран ће остати исти.
Сигурносни образац за асинхроне операције у State-у:
Future<void> _fetchData() async {
final data = await ApiService.fetch();
if (mounted) {
setState(() => _data = data);
}
}
Провера mounted гарантује да се setState позива само за живи State, спречавајући изузетак „setState called after dispose„.
Често постављана питања
StatefulWidget — непроменљива конфигурација виџета, а State — променљиви објекат који чува податке и управља животним циклусом. Виџет може бити поново креиран, State — не. StatefulWidget ствара State кроз createState.
Тачно један. Метод createState се позива једном при првом уграђивању StatefulWidget-а у стабло. Чак и ако се родитељ вишеструко престројава, објекат State остаје исти, све док се не промени тип или Key виџета.
mounted — булова заставица која показује да ли се State налази у стаблу виџета. Након позива dispose, mounted постаје false. Користи се за проверу пре setState у асинхроним колбецима да би се избегао изузетак.
Не. State је увек повезан са одређеним StatefulWidget-ом кроз генерик: State<T extends StatefulWidget>. Креирање State-а директно, без асоцијације са виџетом, архитектонски је немогуће.
Бациће се изузетак: „setState called after dispose„. Након позива dispose, State се сматра мртвим и сваки покушај престројавања UI кроз setState је забрањен. Решење — проверите mounted пре сваког setState.
Резиме
Развићемо мобилну апликацију под кључ
IT Sectr креира iOS и Android апликације за стартапе и предузећа од 2017. године. Саветоваћемо вас и предложити најбоље решење.
Прочитајте такође