StatefulWidget — isang Flutter widget na may nababagong estado, na nagpapahintulot sa UI na tumugon sa mga aksyon ng user, mga asynchronous na kaganapan at mga daloy ng data. Ayon sa opisyal na dokumentasyon ng Flutter (Flutter.dev, 2026), ang StatefulWidget ay ginagamit para sa lahat ng interactive na elemento ng application: mga form ng input, mga animation, mga checkbox, mga switch at mga screen na naglo-load ng data mula sa network. Hindi tulad ng StatelessWidget, lumilikha ito ng isang hiwalay na State object na pinapanatili sa buong lifecycle at maaaring muling itayo nang hindi muling nililikha ang widget mismo.
Mga Pangunahing Punto
StatefulWidget — ay isang Flutter class na maaaring magbago ng estado nito bilang tugon sa mga aksyon ng user, mga kaganapan ng system o mga asynchronous na operasyon. Hindi tulad ng StatelessWidget, ang StatefulWidget ay hindi direktang ipinapakita — lumilikha ito ng isang State object na responsable sa rendering. Ang paghahati sa dalawang klase (Widget at State) ay nagpapahintulot sa Flutter na muling itayo ang UI nang hindi muling nililikha ang widget mismo, na nagbibigay ng malaking bentahe sa pagganap sa mga madalas na pag-update.
Ang arkitektura ng StatefulWidget ay sumusunod sa pattern na «paghihiwalay ng nababago at hindi nababago»: ang widget mismo ay nananatiling hindi nababago (tulad ng StatelessWidget), at ang lahat ng nababagong estado ay naka-imbak sa isang hiwalay na State object. Ito ay nagpapahintulot sa Flutter na muling gamitin ang mga widget sa pamamagitan ng paghahambing sa kanila ayon sa uri at Key, habang pinapanatili ang kasalukuyang estado sa pagitan ng mga muling pagtatayo.
Ayon sa Google (Flutter Architectural Overview, 2026), ang StatefulWidget ay optimal para sa mga senaryo kung saan ang estado ay nagbabago nang higit sa isang beses sa buhay ng widget: mga text field, animation, timer, data stream, asynchronous na pag-load. Para sa isang beses na initialization, sapat na ang StatelessWidget.
StatefulWidget ay sapilitan kapag ang widget ay dapat tumugon sa mga panlabas na kaganapan: pagpindot ng button, pagkumpleto ng HTTP request, pag-update ng data mula sa database, subscription sa WebSocket. Ito rin ay kinakailangan para sa mga widget na may animation, mga text field na may controllers at mga component na namamahala ng focus. Kung ang widget ay nagpapakita lamang ng data at hindi lumilikha ng mga kaganapan — gamitin ang StatelessWidget.
Ang StatefulWidget ay binubuo ng dalawang klase: ang StatefulWidget mismo (magaan, hindi nababago) at State (mabigat, nababago). Ang framework ay lumilikha ng State sa pamamagitan ng createState() method, na tinatawag nang isang beses kapag inilagay sa tree. Ang State ay tumatanggap ng reference sa widget sa pamamagitan ng widget property at maaaring ma-access ang mga field nito anumang oras sa lifecycle.
Lifecycle ng StatefulWidget ay binubuo ng anim na pangunahing yugto, bawat isa ay nagbibigay ng isang overridable na method para sa pagsasagawa ng mga tiyak na gawain. Ang pag-unawa sa mga yugtong ito ay kritikal para sa tamang pagtatrabaho sa mga resource at pag-iwas sa memory leaks.
createState — ang unang method ng lifecycle, na tinatawag kapag ang StatefulWidget ay inilagay sa tree. Dapat itong magbalik ng bagong instance ng State na nauugnay sa widget na ito. Ang method na ito ay tinatawag nang eksaktong isang beses sa buong buhay ng elemento. Mahalaga na huwag magsagawa ng mabibigat na operasyon dito — ang createState ay dapat na gaan hangga’t maaari.
initState — ay tinatawag kaagad pagkatapos ng paglikha ng State, bago ang unang pagtatayo ng UI. Dito isinasagawa ang: initialization ng mga controller (TextEditingController, AnimationController), subscription sa mga data stream (StreamSubscription), pag-setup ng mga timer at paunang initialization ng mga field. Ayon sa Flutter docs (Flutter.dev, 2026), sa initState ay hindi maaaring tumawag ng BuildContext.of() — ang tree ay hindi pa ganap na naka-mount.
didChangeDependencies — ay tinatawag pagkatapos ng initState at sa bawat oras na nagbabago ang mga dependency ng InheritedWidget. Ito ang tamang lugar para tumawag ng MediaQuery.of(context) o mag-subscribe sa Theme — mga value na maaaring magbago habang tumatakbo ang application. Kung ang widget ay gumagamit ng InheritedWidget, ang initialization logic ay dapat na dito, hindi sa initState.
build — ang pangunahing method na nagbabalik ng widget tree. Tinatawag pagkatapos ng initState, pagkatapos ng didChangeDependencies at pagkatapos ng bawat setState. didUpdateWidget ay tinatawag kapag ang parent ay muling nagtatayo at nagpapasa ng StatefulWidget na may mga bagong parameter. Dito maaari mong ihambing ang luma at bagong mga field ng widget at, kung kinakailangan, i-update ang estado.
dispose — ang huling yugto ng lifecycle. Dito pinapalaya ang lahat ng resource: pag-unsubscribe mula sa mga stream, pagtanggal ng mga controller, pagkansela ng mga timer. Ang hindi pagtawag ng dispose ay humahantong sa memory leaks. Pagkatapos ng dispose, ang State ay itinuturing na patay — ang pagtawag ng setState sa loob nito ay nagtatapon ng exception.
Ang mekanismo ng paggawa ng StatefulWidget ay batay sa koordinadong gawain ng tatlong entity: Widget (magaan na paglalarawan), Element (intermediate layer) at State (imbakan ng data). Kapag nakatagpo ang Flutter ng StatefulWidget sa paglalarawan, lumilikha ito ng StatefulElement na tumatawag ng createState at nag-iimbak ng reference sa State object. Sa muling pagtatayo ng parent, inihahambing ng Flutter ang bagong widget sa kasalukuyang Element — kung ang uri at Key ay magkatugma, ang Element ay na-update at ang State ay nananatiling pareho.
Ang estado ay nagbabago lamang sa pamamagitan ng pagtawag ng setState, na nag-aabiso sa framework tungkol sa pangangailangan ng muling pagtatayo. Mahalagang maunawaan: ang setState ay hindi awtomatikong nagbabago ng estado — minamarkahan lamang nito ang widget bilang «marumi». Ang developer mismo ang nag-a-update ng mga field ng State sa callback na ipinasa sa setState. Pagkatapos ng callback, tinatawag ng Flutter ang build at ina-update ang UI.
Ayon sa Dart/Flutter team (Dart Language Specification, 2026), tinitiyak ng paghihiwalay na ito na ang lahat ng pagbabago ng estado ay nangyayari nang synchronously bago ang pagtawag ng build, na inaalis ang sitwasyon kung saan ang UI ay nagpapakita ng bahagyang na-update na data. Ito ang pangunahing mekanismo ng consistency ng interface sa Flutter.
Isaalang-alang natin ang isang simpleng StatefulWidget — isang click counter ng button. Ipinapakita nito ang pangunahing pattern: paglikha ng State, initialization ng field sa initState, pagbabago sa pamamagitan ng setState:
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('Bilang: $_count'),
ElevatedButton(
onPressed: _increment,
child: const Text('Dagdagan'),
),
],
);
}
}
Halimbawa na may asynchronous na pag-load ng data at pamamahala ng lifecycle. Naglo-load ang StatefulWidget ng data mula sa network at nagpapakita ng status ng pag-load:
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('Kumusta, ${_user!.name}');
}
}
Sa pangalawang halimbawa, mahalagang tandaan: sinisimulan ng initState ang isang asynchronous na operasyon, ngunit ang method mismo ay hindi asynchronous. Ang asynchrony ay naisasagawa sa pamamagitan ng async/await sa loob ng hiwalay na method na _loadUser, na nag-a-update ng estado sa pamamagitan ng setState pagkatapos makumpleto ang request. Tinitiyak ng approach na ito na ang widget ay wastong magpapakita ng loading indicator bago makatanggap ng data.
Ang pagpili sa pagitan ng StatefulWidget at StatelessWidget ay hindi lamang tungkol sa pagkakaroon ng estado. Ang StatefulWidget ay nagbibigay ng kumpletong lifecycle na may mga method na initState, didChangeDependencies, didUpdateWidget at dispose, na kinakailangan para sa pagtatrabaho sa mga controller, animation at stream. Ang StatelessWidget naman ay walang mga method na ito at palaging mas magaan para sa framework.
Rekomendasyon ng Flutter team (Flutter docs, 2026) — bawasan ang bilang ng StatefulWidget sa application, sa pamamagitan ng pag-angat ng estado pataas sa tree (State Hoisting) o paggamit ng state management solutions (Riverpod, Bloc, Provider). Bawat StatefulWidget ay lumilikha ng State object na nabubuhay hanggang sa pagtanggal ng elemento — kung mas marami ang naturang widget, mas mataas ang memory load.
| Kriterya | StatefulWidget | StatelessWidget |
|---|---|---|
| Estado | Nababago | Hindi nababago |
| Lifecycle | 6 na yugto | Build lamang |
| State object | Ginawa nang hiwalay | Hindi kinakailangan |
| setState | Magagamit | Hindi magagamit |
| Mga subscription | initState/dispose | Hindi suportado |
| const constructor | Limitado | Ganap na suportado |
| Konsumo ng memorya | Mas mataas | Mas mababa |
StatefulWidget ay nangangailangan ng mas maraming resource kaysa StatelessWidget dahil sa pangangailangan na lumikha at mapanatili ang State object. Gayunpaman, ang tamang paggamit ng StatefulWidget ay hindi humahantong sa mga problema sa pagganap kung susundin ang ilang panuntunan. Una, iwasan ang malalim na nesting ng StatefulWidget — bawat antas ay nagdaragdag ng overhead para sa tree traversal. Pangalawa, hatiin ang kumplikadong StatefulWidget sa ilang simpleng widget, bawat isa ay responsable para sa sarili nitong bahagi ng estado.
Ayon sa Flutter Performance research (Flutter.dev, Pebrero 2026), ang pinakakaraniwang sanhi ng pagbaba ng FPS ay ang pagtawag ng setState sa parent widget na muling nagtatayo ng lahat ng descendants, kabilang ang StatelessWidget na hindi nagbago ang kanilang display. Ang solusyon — ilipat ang nababagong bahagi ng UI sa isang hiwalay na StatefulWidget, upang ang setState ay muling magtayo lamang ng minimum na kinakailangang widget.
Ang paggamit ng const sa loob ng State ay isa pang mahalagang technique. Kung ang child widget ay idineklara bilang const, hindi sila muling itatayo ng Flutter kapag tinawag ang setState sa parent. Pinababawasan nito ang load ng framework at pinaiikli ang oras ng rendering ng frame.
Bawat pagtawag ng setState ay nagti-trigger ng buong muling pagtatayo ng widget. Kung ang estado ay nagbabago nang may mataas na frequency (halimbawa, animation o data stream), isaalang-alang ang paggamit ng AnimatedBuilder, ValueListenableBuilder o StreamBuilder sa halip na manual na pagtawag ng setState. Ang mga widget na ito ay nag-o-optimize ng muling pagtatayo, ina-update lamang ang bahagi ng UI na talagang nagbago.
Ang unang karaniwang pagkakamali sa StatefulWidget — pagtawag ng setState pagkatapos ng dispose. Kapag ang widget ay tinanggal mula sa tree, ang State ay itinuturing na patay at bawat pagtawag ng setState ay nagtatapon ng exception na «setState called after dispose». Kadalasan ito ay nangyayari kapag ang isang asynchronous na operasyon ay natapos pagkatapos tanggalin ang widget. Ang solusyon — suriin ang mounted flag bago tumawag ng setState o kanselahin ang mga asynchronous na operasyon sa dispose.
Ang pangalawang pagkakamali — pagsasagawa ng mabibigat na kalkulasyon sa build method. Dahil ang build ay tinatawag sa bawat setState at sa bawat muling pagtatayo ng parent, lahat ng kalkulasyon ay dapat na gaan hangga’t maaari. Kung kailangan magsagawa ng resource-intensive na operasyon — ilipat ito sa isang hiwalay na Isolate o i-cache ang resulta sa isang State field.
Ang pangatlong pagkakamali — hindi pagtawag ng super.initState() at super.dispose(). Kapag ni-override ang mga method na ito, ang developer ay obligadong tawagin ang parent implementation. Kung hindi ito gagawin, hindi mapamahalaan ng framework ang estado ng Element nang tama, na hahantong sa mga bug na mahirap mahanap.
mounted bago ang setState sa mga asynchronous callbacksuper.initState() at super.dispose()Mga Madalas Itanong
StatefulWidget ay maaaring magbago ng estado nito sa pamamagitan ng setState, may lifecycle (initState, dispose) at lumilikha ng hiwalay na State object. Ang StatelessWidget ay hindi maaaring magbago ng estado at walang lifecycle method — ito ay nagpapakita lamang ng ipinasa na data.
createState ay tinatawag nang eksaktong isang beses para sa bawat instance ng StatefulElement. Kahit na ang parent ay muling magtayo nang maraming beses, hangga’t ang uri at Key ng widget ay hindi nagbabago, ang createState ay hindi tinatawag — ang umiiral na State object ang ginagamit.
Mga resource ay hindi mapapalaya: ang mga controller ay patuloy na gagana sa background, ang mga stream subscription ay mananatiling aktibo, ang mga timer ay hindi makakansela. Ito ay humahantong sa memory leaks at maaaring magdulot ng pagtawag ng setState pagkatapos ng dispose, na nagtatapon ng exception.
Oo, ang constructor ng StatefulWidget ay maaaring maging const. Gayunpaman, hindi ito nagbibigay ng parehong benepisyo tulad ng para sa StatelessWidget — ang State object ay gagawin pa rin sa unang paglalagay. Ang const ay nakakaapekto lamang sa widget mismo (light wrapper), hindi sa State.
didUpdateWidget ay tinatawag kapag ang parent ay nagpapasa ng StatefulWidget na may mga bagong parameter. Ito ay kinakailangan upang i-synchronize ang estado sa bagong data — halimbawa, kung ang userId ay nagbago sa mga parameter, kailangang i-load ang profile ng bagong user.
Buod
Gagawa kami ng mobile application na turnkey
Gumagawa ang IT Sectr ng mga iOS at Android application para sa mga startup at negosyo mula noong 2017. Magpapayo kami sa iyo at magmumungkahi ng pinakamahusay na solusyon.
Basahin din