16 β StatefulWidget va setState¶
β¬ οΈ Oldingi: 15 β Asosiy UI widgetlar Β· π README Β· Keyingi: 17 β Formalar va foydalanuvchi kiritmasi β‘οΈ
Bu bobda: mana, nihoyat β ilovangiz jonlanadi. Shu paytgacha qurgan ekranlaringiz chiroyli edi, lekin harakatsiz: tugmani bossangiz ham hech narsa o'zgarmasdi. Bu bobda biz buni tuzatamiz. Avval 10-bobdagi
UI = f(holat)g'oyasini eslaymiz va negaStatelessWidgeto'zgara olmasligini ko'ramiz. KeyinStatefulWidgetni β uning ikkiga (o'zgarmasWidget+ o'zgaruvchanState) bo'linishini va nega aynan shunday bo'linishini tushunamiz. So'ng bu bobning yuragi βsetStatebilan tanishamiz: holatni o'zgartirib, Flutter'ga "qaytadan qur" deb aytasiz. Birgalikda hisoblagich (counter), kalit (toggle/Switch) va like-tugma quramiz. Undan keyin hayot davri (lifecycle) metodlarini βinitState,dispose,build,mountedβ va kontrollerlar (TextEditingController) namunasini o'rganamiz. Oxirida holatni qayerda saqlash ("lifting state up") vasetStatening chegaralarini ko'rib, eng ko'p uchraydigan xatolarni sanab o'tamiz.
Eslatma: UI = f(holat)¶
10-bobni eslang. Biz Flutter'ning eng muhim g'oyasini bir formula bilan ifodaladik:
UI = f(holat) β interfeys, holatning (state) funksiyasidir.
Ya'ni: sizda biror holat (state) bor, build funksiyasi shu holatni oladi va u uchun mos UI'ni qaytaradi. Holat o'zgarsa, Flutter build'ni qaytadan chaqiradi va yangi UI quradi.
Ammo shu paytgacha qurgan barcha widgetlaringiz StatelessWidget edi. Nomidan ham bilinadi: stateless β "holatsiz". Bunday widget bir marta build qilinadi va undan keyin o'zgarmaydi. Uning maydonlari final (qat'iy), demak ularni keyin o'zgartirib bo'lmaydi.
Lekin haqiqiy ilovalarda ko'p narsa o'zgaradi:
- hisoblagich tugma bosilganda ko'payadi;
- kalit (switch) yoqiladi va o'chiriladi;
- like-tugma bosilganda yurakcha to'ladi;
- formada foydalanuvchi matn kiritadi.
Bularning hammasi uchun sizga holat kerak β widget eslab qoladigan, o'zgaruvchan ma'lumot. Mana shu holatni saqlash va o'zgartirish uchun Flutter'da StatefulWidget bor.
π‘ Aniqlik: "holat" (state) deganda β vaqt o'tishi bilan o'zgaradigan va ekranga ta'sir qiladigan ma'lumotni tushuning.
count = 3,yoqilganmi = true,kiritilganMatn = "Salom"β bularning hammasi holat.
StatefulWidget vs StatelessWidget¶
Endi eng muhim tushunchaga keldik. StatefulWidget ikkita klassdan iborat:
- Widget klassi β
StatefulWidget'dan meros oladi. Bu o'zgarmas (immutable): faqat sozlamalarni (konfiguratsiya) tashiydi, masalan boshlang'ich qiymat yoki sarlavha. Uning maydonlarifinal. - State klassi β
State<T>'dan meros oladi. Bu o'zgaruvchan (mutable): aynan shu yerda holat (o'zgaruvchan maydonlar) vabuildmetodi yashaydi.
Nega ikkiga bo'linadi? Sabab chuqur va muhim. Esingizdami, build juda ko'p marta chaqiriladi va ota widget qayta qurilganda Flutter ko'pincha widget obyektining yangi nusxasini yaratadi. Agar holat shu widget ichida saqlansa, har safar yangi nusxa tug'ilganda holat yo'qolib ketardi (hisoblagich har qayta qurishda nolga qaytib turardi).
Yechim: Widget'ni tashlab, qayta yaratish mumkin β lekin State obyekti xotirada saqlanib qoladi. Flutter widget nusxasini almashtirsa ham, o'sha turdagi State'ni eslab qoladi. Demak holat omon qoladi.
Diagrammada ko'rinib turibdi: chap tarafdagi Widget (konfiguratsiya) qayta-qayta yaratiladi, lekin o'ng tarafdagi State obyekti (count = 0 saqlanadigan joy) doimiy β qayta qurishlarda yo'qolmaydi. Ikkalasini createState metodi bog'laydi.
Mana standart "skelet" (boilerplate). Buni yodlashga urinmang β VS Code'da stful deb yozsangiz, muhit o'zi to'ldirib beradi:
import 'package:flutter/material.dart';
// 1-klass: o'zgarmas Widget (konfiguratsiya)
class Hisoblagich extends StatefulWidget {
const Hisoblagich({super.key});
@override
State<Hisoblagich> createState() => _HisoblagichState();
}
// 2-klass: o'zgaruvchan State (holat + build)
class _HisoblagichState extends State<Hisoblagich> {
int count = 0; // <-- HOLAT: o'zgaruvchan maydon
@override
Widget build(BuildContext context) {
return Text('$count');
}
}
Diqqat qiling:
createState()βWidgetklassining yagona vazifasi: o'ziga mosStateobyektini yaratib qaytarish._HisoblagichStatenomi_(pastki chiziq) bilan boshlanadi β bu Dart'da maxfiy (private) degani. Odatda State klassi shunday yoziladi, chunki u faqat shu faylda kerak.State<Hisoblagich>β burchakli qavs ichida o'z Widget turingizni yozasiz. Bu State'gawidgetorqali Widget konfiguratsiyasiga murojaat qilish imkonini beradi (buni pastda ko'ramiz).- Holat (
int count = 0) βfinalemas, chunki u o'zgarishi kerak. UStateklassining oddiy maydoni.
setState β bu bobning yuragi¶
State'da o'zgaruvchan maydon bor, lekin uni shunchaki o'zgartirsangiz β ekran yangilanmaydi. Nega? Chunki Flutter sizning maydonlaringizni kuzatib turmaydi. U count++ qilganingizni "sezmaydi". Siz unga o'zingiz aytishingiz kerak: "men holatni o'zgartirdim, iltimos meni qaytadan qur".
Mana shu xabarni beradigan metod β setState:
setState ikki ish qiladi bir vaqtda:
- ichidagi funksiyani ishga tushiradi β siz holatni o'zgartirasiz (
count++); - Flutter'ga signal beradi β "bu State o'zgardi, uni qayta qurishni rejalashtir".
Shundan keyin Flutter build'ni qaytadan chaqiradi, build esa yangi count qiymati bilan yangi UI qaytaradi, ekran yangilanadi. Mana to'liq sikl:
π‘ Eng muhim qoida: holatni doim
setStateichida o'zgartiring. Agarcount++nisetState'siz yozsangiz, qiymat xotirada o'zgaradi, lekin ekran yangilanmaydi β Flutter qayta qurish kerakligini bilmaydi. Bu yangi boshlovchilarning eng ko'p uchraydigan xatosi: "kod to'g'ri, lekin ekran qotib turibdi".
setState ichida nima qilmaslik kerak? Faqat holatni o'zgartiring β qisqa, tez ish. setState ichida:
await/asinxron ish qilmang (tarmoqdan ma'lumot yuklash kabi). Avvalawaitbilan ma'lumotni oling, keyin natijanisetStateichida saqlang.- og'ir hisob-kitob qilmang. Hisobni
setStatedan tashqarida bajaring, faqat tayyor natijani ichida saqlang.
// β NOTO'G'RI β asinxron ish setState ichida
setState(() async { // bunday qilmang
data = await api.fetch();
});
// β
TO'G'RI β avval kut, keyin holatni saqla
final natija = await api.fetch();
setState(() {
data = natija; // faqat o'zgartirish
});
Birinchi misol: hisoblagich (counter)¶
Endi nazariyani amalga aylantiramiz. Mana to'liq, ishlaydigan hisoblagich ilovasi. Tugma bosilganda raqam ko'payadi:
import 'package:flutter/material.dart';
void main() => runApp(const MaterialApp(home: HisoblagichSahifa()));
class HisoblagichSahifa extends StatefulWidget {
const HisoblagichSahifa({super.key});
@override
State<HisoblagichSahifa> createState() => _HisoblagichSahifaState();
}
class _HisoblagichSahifaState extends State<HisoblagichSahifa> {
int count = 0; // HOLAT
void _oshir() {
setState(() {
count++; // holatni o'zgartirib, qayta qurishni so'raymiz
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Hisoblagich')),
body: Center(
child: Text(
'$count',
style: const TextStyle(fontSize: 48, fontWeight: FontWeight.bold),
),
),
floatingActionButton: FloatingActionButton(
onPressed: _oshir, // tugma bosilganda _oshir chaqiriladi
child: const Icon(Icons.add),
),
);
}
}
Bu kodni jonli ishga tushiring (flutter run) va "+" tugmasini bir necha marta bosing β raqam o'sib boradi. Nima sodir bo'lyapti?
- Tugma bosiladi β
onPressed_oshir'ni chaqiradi. _oshirichidasetState(() { count++; })βcount0 dan 1 ga oshadi va Flutter'ga "qayta qur" deyiladi.- Flutter
build'ni qayta chaqiradi βText('$count')endi'1'ko'rsatadi. - Ekran yangilanadi.
π‘ Tajriba qiling:
_oshirichidagisetState(...)qatorini olib tashlab, faqatcount++;qoldiring. Ilovani qayta ishga tushiring va tugmani bosing β raqam o'zgarmaydi!countaslida xotirada ko'payib turibdi, lekinsetStatechaqirilmagani uchun Flutterbuild'ni qaytadan ishga tushirmayapti. Mana shu β yuqorida aytgan eng muhim qoidaning amaliy isboti.
Ikkinchi misol: kalit (toggle / Switch)¶
15-bobda Switch widgetini ko'rgan, lekin u "ishlamasdi" β chunki holatni saqlash usulini hali bilmasdik. Endi setState bilan u jonlanadi. Switch ikkita narsani so'raydi: value (hozir yoqilganmi?) va onChanged (foydalanuvchi o'zgartirganda chaqiriladigan callback).
class BildirishnomaKaliti extends StatefulWidget {
const BildirishnomaKaliti({super.key});
@override
State<BildirishnomaKaliti> createState() => _BildirishnomaKalitiState();
}
class _BildirishnomaKalitiState extends State<BildirishnomaKaliti> {
bool yoqilgan = false; // HOLAT
@override
Widget build(BuildContext context) {
return SwitchListTile(
title: const Text('Bildirishnomalar'),
value: yoqilgan, // UI holatni aks ettiradi
onChanged: (yangiQiymat) {
setState(() {
yoqilgan = yangiQiymat; // holatni yangilaymiz
});
},
);
}
}
E'tibor bering β value: yoqilgan deyapmiz, ya'ni kalit ko'rinishi holatdan kelib chiqadi (UI = f(holat)). Foydalanuvchi kalitni surganda onChanged chaqiriladi, biz setState ichida yoqilganni yangilaymiz, Flutter build'ni qayta chaqiradi va kalit yangi holatda chiziladi. Siz kalitni "qo'lda" surmaysiz β faqat holatni o'zgartirasiz.
π‘
SwitchListTileβ buSwitch+ matn (sarlavha) ni birga beradigan qulay widget. Faqat kalit kerak bo'lsa, oddiySwitch(value: ..., onChanged: ...)ishlatishingiz mumkin.
Uchinchi misol: like-tugma¶
Endi o'rganganingizni mustahkamlash uchun like-tugma quramiz: bosilganda yurakcha to'ladi yoki bo'shaydi, va yoqtirganlar soni o'zgaradi. Bu yerda ikkita holat bor:
class LikeTugma extends StatefulWidget {
const LikeTugma({super.key});
@override
State<LikeTugma> createState() => _LikeTugmaState();
}
class _LikeTugmaState extends State<LikeTugma> {
bool yoqtirilgan = false; // HOLAT 1
int soni = 0; // HOLAT 2
void _almashtir() {
setState(() {
yoqtirilgan = !yoqtirilgan; // teskarisiga o'tkazamiz
soni += yoqtirilgan ? 1 : -1; // sonni mosga keltiramiz
});
}
@override
Widget build(BuildContext context) {
return Row(
mainAxisSize: MainAxisSize.min,
children: [
IconButton(
onPressed: _almashtir,
icon: Icon(
yoqtirilgan ? Icons.favorite : Icons.favorite_border,
color: yoqtirilgan ? Colors.red : null,
),
),
Text('$soni'),
],
);
}
}
Bu misolda muhim bir narsa ko'rinadi: bitta setState ichida bir nechta holatni birga o'zgartirish mumkin (yoqtirilgan va soni). Flutter ulardan keyin bir marta qayta quradi. Ikonkaning ko'rinishi (favorite yoki favorite_border) va rangi to'liq holatdan kelib chiqadi β yana o'sha UI = f(holat).
Hayot davri (lifecycle) metodlari¶
State obyekti tug'iladi, yashaydi (ko'p marta build qilinadi) va o'ladi. Bu yo'l davomida Flutter ma'lum nuqtalarda sizning State'ingizdagi maxsus metodlarni chaqiradi. Bularni hayot davri (lifecycle) metodlari deyiladi. Mana ularning tartibi:
Eng muhim ikkitasi β initState (boshida, sozlash uchun) va dispose (oxirida, tozalash uchun):
createState()β State obyektini yaratadi. Bir marta. (Buni odatda o'zgartirmaysiz.)initState()β State birinchi marta yaratilganda bir marta chaqiriladi,build'dan oldin. Bu yerda boshlang'ich sozlash qilinadi: kontrollerlar yaratish, obunaga yozilish (subscription), boshlang'ich ma'lumotni yuklash. β οΈ Bu yerdacontextga bog'liq ishlarni (masalanTheme.of(context)) qilmang β buning uchundidChangeDependenciesbor.didChangeDependencies()βinitState'dan keyin va keyinroq bog'liqliklar o'zgarganda chaqiriladi.contextga bog'liq sozlash uchun. (Boshida kamroq kerak bo'ladi.)didUpdateWidget(eski)β ota widget yangi konfiguratsiya (yangiWidgetnusxasi) bergan paytda chaqiriladi. Yangi sozlama eskidan farq qilsa, mos amalni shu yerda qilasiz.build()β UI'ni quradi. Har bir qayta qurishda ishlaydi (harsetStateda). Tez va toza bo'lishi shart.dispose()β State butunlay o'chirilganda (widget daraxtdan olib tashlanganda) bir marta chaqiriladi. Bu yerda tozalash qilinadi: kontrollerlarnidisposeqilish, obunalarni bekor qilish. β οΈ Buni unutsangiz β xotira oqimi (memory leak) bo'ladi.
Mana hayot davrini ko'rsatadigan kichik misol. Konsolda chiqishni kuzating:
class HayotDavri extends StatefulWidget {
const HayotDavri({super.key});
@override
State<HayotDavri> createState() => _HayotDavriState();
}
class _HayotDavriState extends State<HayotDavri> {
@override
void initState() {
super.initState(); // har doim super'ni chaqiring
debugPrint('initState β bir marta: sozlash');
}
@override
Widget build(BuildContext context) {
debugPrint('build β har qayta qurishda');
return const Text('Hayot davri misoli');
}
@override
void dispose() {
debugPrint('dispose β bir marta: tozalash');
super.dispose(); // dispose'da super'ni OXIRIDA chaqiring
}
}
π‘ Qoida:
initState'dasuper.initState()ni birinchi,dispose'dasuper.dispose()ni oxirgi qator qilib chaqiring. Aks holda Flutter ogohlantirish beradi.
Kontrollerlar namunasi: yarat, ishlat, dispose qil¶
Ko'p widgetlar (matn maydoni, animatsiya, ro'yxat) kontroller orqali boshqariladi. Kontroller β bu vaqt o'tishi bilan yashaydigan, xotira egallaydigan obyekt. Shuning uchun u uchta bosqichdan o'tadi: initState'da yaratiladi, build'da ishlatiladi, dispose'da tozalanadi.
class IzohMaydoni extends StatefulWidget {
const IzohMaydoni({super.key});
@override
State<IzohMaydoni> createState() => _IzohMaydoniState();
}
class _IzohMaydoniState extends State<IzohMaydoni> {
// odatda kontrollerni 'late final' maydon qilib e'lon qilamiz
late final TextEditingController _kontroller;
@override
void initState() {
super.initState();
_kontroller = TextEditingController(); // 1. YARAT
}
@override
Widget build(BuildContext context) {
return TextField(
controller: _kontroller, // 2. ISHLAT
decoration: const InputDecoration(labelText: 'Izoh yozing'),
);
}
@override
void dispose() {
_kontroller.dispose(); // 3. TOZALA β bu juda muhim!
super.dispose();
}
}
Nega dispose shunchalik muhim? TextEditingController (va AnimationController, oqimlarga obuna kabilar) xotira va resurs egallaydi. Agar State o'chirilganda ularni dispose qilmasangiz, ular xotirada osilib qoladi β bu xotira oqimi (memory leak). Ilova vaqt o'tgan sari sekinlashadi va ko'p xotira "yeydi". Qoida oddiy: yaratgan har bir kontrollerni dispose qiling.
π‘
TextFieldva formalar bilan to'liq ishlashni 17-bobda chuqur ko'ramiz. Hozir asosiy namunani eslang: yarat (initState) β ishlat (build) β tozala (dispose).
mounted β async'dan keyin himoya¶
Bitta nozik holat bor. Tasavvur qiling, tugma bosilganda tarmoqdan ma'lumot yuklayapsiz (await), keyin natijani setState bilan saqlamoqchisiz. Lekin yuklash davom etayotganda foydalanuvchi sahifadan chiqib ketishi mumkin β o'shanda State o'chiriladi (dispose bo'ladi). O'chgan State'da setState chaqirsangiz β Flutter xato beradi.
Yechim β mounted maydonini tekshirish. mounted β State hozir ham daraxtda ("ulangan") yoki yo'qligini bildiradigan bool:
Future<void> _yukla() async {
final natija = await api.malumotOl(); // kutish davomida
if (!mounted) return; // State o'chgan bo'lsa β to'xtaymiz
setState(() {
data = natija;
});
}
Qoida: await'dan keyin setState chaqirishdan oldin if (!mounted) return; yozing.
Holatni qayerda saqlash? "Lifting state up"¶
Endi muhim savol: holat qaysi widgetda yashashi kerak? Tasavvur qiling, ikki widget bitta holatga bog'liq β masalan, bitta tugma sonni oshiradi, boshqa joyda esa o'sha son ko'rsatiladi. Holat qayerda turishi kerak?
Javob: holatni ikkala widgetning eng yaqin umumiy "ota"sida saqlang. Bu yondashuv "holatni yuqoriga ko'tarish" (lifting state up) deyiladi. Keyin:
- ma'lumotni pastga β bolalarga konstruktor orqali uzatasiz (
Bola(qiymat: count)); - hodisalarni yuqoriga β callback (funksiya) orqali qaytarasiz (
Tugma(onBosildi: _oshir)).
// Ota: holat shu yerda yashaydi
class Ota extends StatefulWidget {
const Ota({super.key});
@override
State<Ota> createState() => _OtaState();
}
class _OtaState extends State<Ota> {
int count = 0;
@override
Widget build(BuildContext context) {
return Column(
children: [
KorsatuvchiBola(qiymat: count), // ma'lumot PASTGA
TugmaBola(
onBosildi: () => setState(() => count++), // callback YUQORIGA
),
],
);
}
}
Bu yerda KorsatuvchiBola va TugmaBola β oddiy StatelessWidget bo'lishi mumkin; ular holatni saqlamaydi, faqat ota bergan ma'lumotni ko'rsatadi va hodisani ortga qaytaradi.
setState'ning chegaralari β keyingi qadam¶
setState ajoyib, lekin uning chegarasi bor. Ilova kattalashganda holat ko'pincha chuqurda kerak bo'ladi: ota β bola β nabira β chevara... Holatni shu zanjir bo'ylab konstruktor orqali qatma-qat uzatish kerak bo'lib qoladi β buni "prop-drilling" (qiymatni qatlamlar orasidan o'tkazib o'tkazish) deyiladi. Bu zerikarli va xatoga moyil.
Aynan shu muammoni hal qilish uchun holat boshqaruvi (state management) vositalari bor. Ular holatni bitta markaziy joyda saqlab, kerakli widgetga to'g'ridan-to'g'ri yetkazadi β qatma-qat uzatishsiz. Biz bulardan birini β Providerni β 24-bobda o'rganamiz. Hozircha esa setState mahalliy (lokal) holat uchun, ayniqsa o'rganishning shu bosqichida, mukammal vosita.
Eng ko'p uchraydigan xatolar¶
Yangi boshlovchilar setState bilan ko'p adashadi. Mana eng tez-tez uchraydiganlari:
setStatesiz o'zgartirish.count++deysiz, lekinsetStateichida emas β ekran yangilanmaydi. Holatni doimsetStateichida o'zgartiring.buildichidasetStatechaqirish. Bu cheksiz sikl keltirib chiqaradi:buildβsetStateβ qaytabuildβ yanasetState... Ilova qotadi.setStateni hodisalardan (onPressedkabi) yoki hayot davri metodlaridan chaqiring, hech qachonbuildichidan emas.buildichida og'ir ish. Tarmoq so'rovi, fayl o'qish, og'ir hisob β bularnibuildichida qilmang.buildko'p marta chaqiriladi; bunday ishlarniinitState'da yoki hodisalarda bajaring.disposeni unutish. Kontroller yaratdingiz, lekindisposeqilmadingiz β xotira oqimi. Yaratgan har bir kontrollernidisposeqiling.disposedan keyinsetState. Asinxron ishdan keyin State o'chgan bo'lishi mumkin.awaitdan keyinif (!mounted) return;bilan himoyalaning.
Keyingi qadam¶
Tabriklaymiz β ilovangiz endi jonli! Siz Flutter'ning interaktivlik yuragini o'rgandingiz: StatefulWidget holatni Widget+State bo'linishi orqali saqlaydi, setState esa holatni o'zgartirib qayta qurishni boshlaydi. Hayot davri metodlari (initState/dispose) va mounted bilan resurslarni to'g'ri boshqarishni ko'rdingiz.
Keyingi 17-bobda bu bilimni amalga oshirib, formalar va foydalanuvchi kiritmasi bilan ishlaymiz: TextField, TextEditingController, validatsiya (tekshirish) va Form widgeti. Holatni butun ilova bo'ylab keng tarqatish β Provider bilan β esa 24-bobda keladi.
Mashqlar¶
Oson¶
- O'z so'zlaringiz bilan ayting: nega
StatefulWidgetikkita klassga (WidgetvaState) bo'linadi? Qaysi biri o'zgarmas, qaysi biri o'zgaruvchan? setStateikkita ishni bir vaqtda qiladi. Bu ikki ish nima?- Bir o'quvchi
count++;deb yozdi (setStatesiz), lekin ekran yangilanmayapti. Sabab nimada? Tuzating. initStatevadisposemetodlari nima uchun? Har biriga bittadan amaliy misol (nima qilinadi) keltiring.
O'rta¶
- To'liq, kompilyatsiya bo'ladigan hisoblagich ilovasini yozing, lekin endi ikkita tugma bilan: biri sonni oshiradi (
+), ikkinchisi kamaytiradi (-). Son markazda ko'rinsin. TextEditingControllerishlatadigan kichikStatefulWidgetyozing: uinitState'da kontroller yaratsin,build'daTextFieldda ishlatsin vadispose'da tozalasin. Negadisposeshart ekanini bir jumlada izohlang.- Quyidagi xatoni toping va tuzating: dasturchi
buildmetodi ichidasetState(() => count++);yozib qo'ygan. Nima bo'ladi va nega?
Qiyin¶
- "Lifting state up" g'oyasini tushuntiring: holatni qayerda saqlash kerak, ma'lumot qaysi tomonga (yuqoriga yoki pastga) va callback qaysi tomonga uzatiladi? Kichik kod yoki diagramma bilan ko'rsating.
- Tugma bosilganda asinxron
await api.malumotOl()chaqirib, natijanisetStatebilan saqlaydigan metod yozing.mountedtekshiruvini qo'ying va nega kerakligini izohlang. setStatening chegarasi nimada? "Prop-drilling" nima va u qachon muammoga aylanadi? Bu muammoni qaysi yondashuv hal qiladi (kelajakdagi bobga ishora qilib)?
Yechimlar
1. StatefulWidget ikkiga bo'linadi, chunki widget obyekti tez-tez qayta yaratiladi (ota har qayta qurganda yangi nusxa tug'ilishi mumkin), lekin holat saqlanib qolishi kerak. Widget klassi β o'zgarmas (immutable), faqat konfiguratsiyani tashiydi, maydonlari final. State klassi β o'zgaruvchan (mutable), holat (o'zgaruvchan maydonlar) va build shu yerda yashaydi va u qayta qurishlarda xotirada saqlanib qoladi.
2. setState: (1) o'ziga berilgan funksiyani ishga tushiradi β siz holatni shu yerda o'zgartirasiz; (2) Flutter'ga "bu State o'zgardi, qayta qurishni rejalashtir" deb signal beradi. Shuning uchun build qaytadan chaqiriladi va UI yangilanadi.
3. count++ setState ichida emas β Flutter holat o'zgarganini bilmaydi, shuning uchun build'ni qaytadan chaqirmaydi va ekran eski qiymatda qotib qoladi. Tuzatish:
4.
- initState β State birinchi marta yaratilganda bir marta, build'dan oldin chaqiriladi; sozlash uchun. Misol: _kontroller = TextEditingController(); (kontroller yaratish), yoki boshlang'ich ma'lumotni yuklashni boshlash.
- dispose β State o'chirilganda bir marta chaqiriladi; tozalash uchun. Misol: _kontroller.dispose(); (kontrollerni tozalash) yoki oqim obunasini bekor qilish β xotira oqimining oldini olish.
5.
import 'package:flutter/material.dart';
void main() => runApp(const MaterialApp(home: Hisoblagich()));
class Hisoblagich extends StatefulWidget {
const Hisoblagich({super.key});
@override
State<Hisoblagich> createState() => _HisoblagichState();
}
class _HisoblagichState extends State<Hisoblagich> {
int count = 0;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Hisoblagich')),
body: Center(
child: Text(
'$count',
style: const TextStyle(fontSize: 48, fontWeight: FontWeight.bold),
),
),
floatingActionButton: Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
FloatingActionButton(
onPressed: () => setState(() => count--),
child: const Icon(Icons.remove),
),
const SizedBox(width: 12),
FloatingActionButton(
onPressed: () => setState(() => count++),
child: const Icon(Icons.add),
),
],
),
);
}
}
6.
class IzohMaydoni extends StatefulWidget {
const IzohMaydoni({super.key});
@override
State<IzohMaydoni> createState() => _IzohMaydoniState();
}
class _IzohMaydoniState extends State<IzohMaydoni> {
late final TextEditingController _kontroller;
@override
void initState() {
super.initState();
_kontroller = TextEditingController();
}
@override
Widget build(BuildContext context) {
return TextField(controller: _kontroller);
}
@override
void dispose() {
_kontroller.dispose();
super.dispose();
}
}
dispose shart, chunki TextEditingController xotira/resurs egallaydi; uni tozalamasak xotira oqimi (memory leak) bo'ladi.
7. build ichida setState chaqirilsa, u qayta qurishni rejalashtiradi β build yana ishlaydi β yana setState... bu cheksiz siklga olib keladi, ilova qotadi (yoki Flutter xato beradi). Tuzatish: setStateni build ichidan olib tashlang va uni faqat hodisalardan (onPressed kabi) yoki hayot davri metodidan chaqiring. Boshlang'ich qiymat kerak bo'lsa, uni maydon e'lonida yoki initState'da bering.
8. Holatni ikki (yoki undan ko'p) widgetning eng yaqin umumiy otasida saqlash kerak ("lifting state up"). Ma'lumot pastga uzatiladi β ota bolaga konstruktor orqali qiymat beradi (Bola(qiymat: count)). Callback (funksiya) yuqoriga uzatiladi β bola hodisani ota bergan funksiya orqali ortga qaytaradi (Tugma(onBosildi: () => setState(...))). Shunda holatga ta'sir qiladigan widgetlar bir manbadan boshqariladi va sinxron qoladi.
9.
Future<void> _yukla() async {
final natija = await api.malumotOl();
if (!mounted) return; // State o'chgan bo'lsa to'xtaymiz
setState(() {
data = natija;
});
}
mounted tekshiruvi kerak, chunki await davomida (kutish paytida) foydalanuvchi sahifadan chiqib ketishi va State o'chirilishi (dispose) mumkin. O'chgan State'da setState chaqirilsa, Flutter xato beradi. if (!mounted) return; shu holatda metodni xavfsiz to'xtatadi.
10. setState faqat mahalliy (lokal) holat uchun qulay. Ilova kattalashganda holat chuqurda (ota β bola β nabira β ...) kerak bo'lib qoladi va uni shu zanjir bo'ylab konstruktor orqali qatma-qat uzatishga to'g'ri keladi β bu "prop-drilling". U zerikarli, ko'p kod talab qiladi va xatoga moyil: oraliq widgetlar o'zlariga kerak bo'lmagan ma'lumotni faqat "o'tkazib berish" uchun qabul qiladi. Buni holat boshqaruvi (state management) hal qiladi β masalan Provider (24-bob) β holatni markaziy joyda saqlab, kerakli widgetga to'g'ridan-to'g'ri yetkazadi.
β¬ οΈ Oldingi: 15 β Asosiy UI widgetlar Β· π README Β· Keyingi: 17 β Formalar va foydalanuvchi kiritmasi β‘οΈ