StatefulWidget ایک Flutter ویجٹ ہے جس میں قابل تبدیلی حالت ہوتی ہے، جو UI کو صارف کے اعمال، غیر متزامن واقعات اور ڈیٹا سٹریمز پر رد عمل ظاہر کرنے کی اجازت دیتا ہے۔ آفیشل Flutter دستاویزات (Flutter.dev، 2026) کے مطابق، StatefulWidget ایپلیکیشن کے تمام انٹرایکٹو عناصر کے لیے استعمال ہوتا ہے: ان پٹ فارم، اینیمیشن، چیک باکس، سوئچز اور اسکرینز جو نیٹ ورک سے ڈیٹا لوڈ کرتی ہیں۔ StatelessWidget کے برعکس، یہ ایک علیحدہ State آبجیکٹ بناتا ہے جو اس کے پورے لائف سائیکل میں برقرار رہتا ہے اور ویجٹ کو دوبارہ بنائے بغیر دوبارہ تعمیر کیا جا سکتا ہے۔
اہم نکات
StatefulWidget ایک Flutter کلاس ہے جو صارف کے اعمال، سسٹم ایونٹس یا غیر متزامن کارروائیوں کے جواب میں اپنی حالت تبدیل کر سکتی ہے۔ StatelessWidget کے برعکس، StatefulWidget براہ راست رینڈر نہیں ہوتا — یہ ایک State آبجیکٹ بناتا ہے جو رینڈرنگ کو سنبھالتا ہے۔ دو کلاسز (Widget اور State) میں یہ تقسیم Flutter کو ویجٹ کو دوبارہ بنائے بغیر UI کو دوبارہ تعمیر کرنے کی اجازت دیتی ہے، جو بار بار اپ ڈیٹس کے دوران کارکردگی کا اہم فائدہ فراہم کرتی ہے۔
StatefulWidget کا فن تعمیر “قابل تبدیلی اور ناقابل تبدیلی کی علیحدگی” کے پیٹرن کی پیروی کرتا ہے: ویجٹ خود ناقابل تبدیلی رہتا ہے (StatelessWidget کی طرح)، جبکہ تمام قابل تبدیلی حالت ایک علیحدہ State آبجیکٹ میں محفوظ کی جاتی ہے۔ یہ Flutter کو قسم اور Key کے ذریعے موازنہ کرکے ویجٹ کو دوبارہ استعمال کرنے کی اجازت دیتا ہے، اور ساتھ ہی دوبارہ تعمیروں کے درمیان اصل حالت کو محفوظ رکھتا ہے۔
Google (Flutter Architectural Overview، 2026) کے مطابق، StatefulWidget ان منظرناموں کے لیے بہترین ہے جہاں ویجٹ کی زندگی میں حالت ایک سے زیادہ بار تبدیل ہوتی ہے: ٹیکسٹ فیلڈز، اینیمیشن، ٹائمر، ڈیٹا سٹریمز، غیر متزامن لوڈ۔ ایک بار کے ابتدائیے کے لیے، StatelessWidget کافی ہے۔
StatefulWidget لازمی ہے جب ویجٹ کو بیرونی واقعات پر رد عمل ظاہر کرنا ہو: بٹن کلک، HTTP درخواستوں کی تکمیل، ڈیٹابیس ڈیٹا اپ ڈیٹ، WebSocket سبسکرپشنز۔ یہ اینیمیشن والے ویجٹ، کنٹرولر والے ٹیکسٹ فیلڈز اور فوکس کو منظم کرنے والے اجزاء کے لیے بھی ضروری ہے۔ اگر کوئی ویجٹ صرف ڈیٹا ظاہر کرتا ہے اور واقعات پیدا نہیں کرتا، تو StatelessWidget استعمال کریں۔
StatefulWidget دو کلاسز پر مشتمل ہے: خود StatefulWidget (ہلکا، ناقابل تبدیلی) اور State (بھاری، قابل تبدیلی)۔ فریم ورک createState() طریقہ کے ذریعے State بناتا ہے، جو درخت میں داخل کرنے پر ایک بار بلایا جاتا ہے۔ State کو widget خاصیت کے ذریعے ویجٹ کا حوالہ ملتا ہے اور لائف سائیکل کے کسی بھی موقع پر اس کے فیلڈز تک رسائی حاصل کر سکتا ہے۔
لائف سائیکل چھ اہم مراحل پر مشتمل ہے، جن میں سے ہر ایک مخصوص کاموں کو انجام دینے کے لیے اوور رائڈ قابل طریقہ فراہم کرتا ہے۔ ان مراحل کو سمجھنا وسائل کے مناسب انتظام اور میموری لیک سے بچنے کے لیے اہم ہے۔
createState لائف سائیکل کا پہلا طریقہ ہے، جو StatefulWidget کو درخت میں داخل کرنے پر بلایا جاتا ہے۔ اسے اس ویجٹ سے وابستہ ایک نیا State انسٹنس واپس کرنا چاہیے۔ یہ طریقہ عنصر کی پوری زندگی میں ٹھیک ایک بار بلایا جاتا ہے۔ یہاں بھاری کارروائیاں نہ کرنا ضروری ہے — createState جتنا ممکن ہو ہلکا ہونا چاہیے۔
initState State بننے کے فوراً بعد، پہلی UI تعمیر سے پہلے بلایا جاتا ہے۔ یہاں کیا جاتا ہے: کنٹرولرز کا ابتدائیہ (TextEditingController، AnimationController)، ڈیٹا سٹریمز کی سبسکرائب (StreamSubscription)، ٹائمر سیٹ اپ اور فیلڈز کا ابتدائی آغاز۔ Flutter دستاویزات (Flutter.dev، 2026) کے مطابق، initState میں BuildContext.of() کو نہیں بلایا جا سکتا — درخت ابھی مکمل طور پر ماؤنٹ نہیں ہوا ہے۔
didChangeDependencies initState کے بعد اور InheritedWidget انحصار تبدیل ہونے پر ہر بار بلایا جاتا ہے۔ یہ MediaQuery.of(context) کو بلانے یا Theme کو سبسکرائب کرنے کے لیے مناسب جگہ ہے — وہ اقدار جو ایپلیکیشن کے رن ٹائم کے دوران تبدیل ہو سکتی ہیں۔ اگر کوئی ویجٹ InheritedWidget استعمال کرتا ہے، تو ابتدائیہ منطق یہاں ہونی چاہیے، initState میں نہیں۔
build اہم طریقہ ہے جو ویجٹ درخت واپس کرتا ہے۔ یہ initState کے بعد، didChangeDependencies کے بعد اور ہر setState کے بعد بلایا جاتا ہے۔ didUpdateWidget اس وقت بلایا جاتا ہے جب والدین دوبارہ تعمیر کرتے ہیں اور نئے پیرامیٹرز کے ساتھ StatefulWidget منتقل کرتے ہیں۔ یہاں پرانے اور نئے ویجٹ فیلڈز کا موازنہ کیا جا سکتا ہے اور اگر ضروری ہو تو حالت کو اپ ڈیٹ کیا جا سکتا ہے۔
dispose لائف سائیکل کا آخری مرحلہ ہے۔ یہاں تمام وسائل آزاد کیے جاتے ہیں: سٹریم سے سبسکرپشنز منسوخ، کنٹرولرز ہٹائے جاتے ہیں، ٹائمر منسوخ کیے جاتے ہیں۔ dispose کو نہ بلانا میموری لیک کا باعث بنتا ہے۔ dispose کے بعد، State مردہ سمجھا جاتا ہے — اس کے اندر setState بلانا استثنا پھینکتا ہے۔
StatefulWidget کے کام کرنے کا طریقہ کار تین ہستیوں کے مربوط کام پر مبنی ہے: Widget (ہلکی تفصیل)، Element (درمیانی پرت) اور State (ڈیٹا ذخیرہ)۔ جب Flutter تفصیل میں StatefulWidget پاتا ہے، یہ StatefulElement بناتا ہے، جو createState کو بلاتا ہے اور State آبجیکٹ کا حوالہ محفوظ کرتا ہے۔ جب والدین دوبارہ تعمیر کرتا ہے، Flutter نئے ویجٹ کا موجودہ Element سے موازنہ کرتا ہے — اگر قسم اور Key مماثل ہوں، Element اپ ڈیٹ ہوتا ہے اور State وہی رہتا ہے۔
حالت صرف setState کال کے ذریعے تبدیل ہوتی ہے، جو فریم ورک کو دوبارہ تعمیر کی ضرورت سے آگاہ کرتی ہے۔ یہ سمجھنا اہم ہے: setState خود بخود حالت نہیں بدلتا — یہ صرف ویجٹ کو “گندا” نشان زد کرتا ہے۔ ڈویلپر آزادانہ طور پر setState کو بھیجے گئے کال بیک میں State فیلڈز کو اپ ڈیٹ کرتا ہے۔ کال بیک مکمل ہونے کے بعد، Flutter build کو بلاتا ہے اور UI کو اپ ڈیٹ کرتا ہے۔
Dart/Flutter ٹیم (Dart Language Specification، 2026) کے مطابق، یہ علیحدگی اس بات کو یقینی بناتی ہے کہ build بلائے جانے سے پہلے تمام حالت تبدیلیاں ہم وقت ہوتی ہیں، اس صورت حال کو ختم کرتے ہوئے جہاں UI جزوی طور پر اپ ڈیٹ شدہ ڈیٹا ظاہر کرتا ہے۔ یہ Flutter میں انٹرفیس مستقل مزاجی کا ایک اہم طریقہ کار ہے۔
آئیے ایک سادہ StatefulWidget دیکھتے ہیں — ایک بٹن کلک کاؤنٹر۔ یہ بنیادی پیٹرن ظاہر کرتا ہے: State بنانا، initState میں فیلڈ شروع کرنا، 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('Count: $_count'),
ElevatedButton(
onPressed: _increment,
child: const Text('Increment'),
),
],
);
}
}
غیر متزامن ڈیٹا لوڈنگ اور لائف سائیکل مینجمنٹ کے ساتھ ایک مثال۔ StatefulWidget نیٹ ورک سے ڈیٹا لوڈ کرتا ہے اور لوڈنگ کی حالت ظاہر کرتا ہے:
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('Hello, ${_user!.name}');
}
}
دوسری مثال میں، یہ نوٹ کرنا اہم ہے: initState ایک غیر متزامن کارروائی شروع کرتا ہے، لیکن طریقہ خود غیر متزامن نہیں ہے۔ غیر متزامنیت ایک علیحدہ طریقہ _loadUser کے اندر async/await کے ذریعے لاگو کی گئی ہے، جو درخواست مکمل ہونے کے بعد setState کے ذریعے حالت کو اپ ڈیٹ کرتا ہے۔ یہ طریقہ یقینی بناتا ہے کہ ویجٹ ڈیٹا وصول کرنے سے پہلے لوڈنگ اشارے کو صحیح طریقے سے ظاہر کرتا ہے۔
StatefulWidget اور StatelessWidget کے درمیان انتخاب صرف حالت رکھنے کے بارے میں نہیں ہے۔ StatefulWidget initState، didChangeDependencies، didUpdateWidget اور dispose طریقوں کے ساتھ ایک مکمل لائف سائیکل فراہم کرتا ہے، جو کنٹرولرز، اینیمیشن اور سٹریمز کے ساتھ کام کرنے کے لیے ضروری ہیں۔ StatelessWidget، دوسری طرف، ان طریقوں کو نہیں رکھتا اور فریم ورک کے لیے ہمیشہ ہلکا ہوتا ہے۔
Flutter ٹیم کی سفارش (Flutter docs، 2026) ایپلیکیشن میں StatefulWidgets کی تعداد کو کم سے کم کرنا ہے، حالت کو درخت میں اوپر اٹھا کر (State Hoisting) یا حالت کے انتظام کے حل (Riverpod، Bloc، Provider) استعمال کر کے۔ ہر StatefulWidget ایک State آبجیکٹ بناتا ہے جو عنصر ہٹائے جانے تک زندہ رہتا ہے — جتنے زیادہ ایسے ویجٹ ہوں گے، میموری کا بوجھ اتنا ہی زیادہ ہوگا۔
| معیار | StatefulWidget | StatelessWidget |
|---|---|---|
| حالت | قابل تبدیلی | ناقابل تبدیلی |
| لائف سائیکل | 6 مراحل | صرف build |
| State آبجیکٹ | علیحدہ بنایا گیا | ضروری نہیں |
| setState | دستیاب | دستیاب نہیں |
| سبسکرپشنز | initState/dispose | تعاون یافتہ نہیں |
| const کنسٹرکٹر | محدود | مکمل تعاون یافتہ |
| میموری کھپت | زیادہ | کم |
StatefulWidget کو State آبجیکٹ بنانے اور برقرار رکھنے کی ضرورت کی وجہ سے StatelessWidget سے زیادہ وسائل درکار ہوتے ہیں۔ تاہم، StatefulWidget کا صحیح استعمال کارکردگی کے مسائل کا سبب نہیں بنتا اگر چند اصولوں پر عمل کیا جائے۔ پہلا، StatefulWidget کی گہری نیسٹنگ سے بچیں — ہر سطح درخت کی گردش میں اوورہیڈ شامل کرتی ہے۔ دوسرا، پیچیدہ StatefulWidget کو کئی سادہ ویجٹ میں تقسیم کریں، ہر ایک حالت کے اپنے حصے کے لیے ذمہ دار ہے۔
Flutter کارکردگی تحقیق (Flutter.dev، فروری 2026) کے مطابق، FPS گرنے کی سب سے عام وجہ والدین ویجٹ میں setState کال کرنا ہے جو تمام اولاد کو دوبارہ تعمیر کرتا ہے، بشمول StatelessWidgets جنہوں نے اپنا ڈسپلے تبدیل نہیں کیا۔ حل UI کے قابل تبدیلی حصے کو ایک علیحدہ StatefulWidget میں نکالنا ہے تاکہ setState صرف کم سے کم ضروری ویجٹ کو دوبارہ تعمیر کرے۔
State کے اندر const استعمال کرنا ایک اور اہم تکنیک ہے۔ اگر بچے ویجٹ کو const کے طور پر اعلان کیا جائے، Flutter والدین میں setState بلانے پر انہیں دوبارہ تعمیر نہیں کرے گا۔ یہ فریم ورک پر بوجھ کم کرتا ہے اور فریم رینڈرنگ وقت گھٹاتا ہے۔
ہر setState کال مکمل ویجٹ دوبارہ تعمیر کو متحرک کرتی ہے۔ اگر حالت زیادہ تعدد کے ساتھ تبدیل ہوتی ہے (مثال کے طور پر، اینیمیشن یا ڈیٹا سٹریم)، دستی طور پر setState کال کرنے کے بجائے AnimatedBuilder، ValueListenableBuilder یا StreamBuilder استعمال کرنے پر غور کریں۔ یہ ویجٹ دوبارہ تعمیر کو بہتر بناتے ہیں، صرف UI کے اس حصے کو اپ ڈیٹ کرتے ہیں جو حقیقت میں تبدیل ہوا ہے۔
StatefulWidget کے ساتھ پہلی عام غلطی dispose کے بعد setState کال کرنا ہے۔ جب ویجٹ درخت سے ہٹا دیا جاتا ہے، State مردہ سمجھا جاتا ہے، اور کوئی بھی setState کال “setState called after dispose” استثنا پھینکتی ہے۔ یہ اکثر اس وقت ہوتا ہے جب ویجٹ ہٹائے جانے کے بعد کوئی غیر متزامن کارروائی مکمل ہوتی ہے۔ حل setState کال کرنے سے پہلے mounted پرچم چیک کرنا یا dispose میں غیر متزامن کارروائیاں منسوخ کرنا ہے۔
دوسری غلطی build طریقہ میں بھاری حساب کتاب کرنا ہے۔ چونکہ build ہر setState اور ہر والدین دوبارہ تعمیر پر بلایا جاتا ہے، تمام حسابات جتنا ممکن ہو ہلکے ہونے چاہئیں۔ اگر وسائل پر بھاری کارروائی کی ضرورت ہے، اسے علیحدہ Isolate میں منتقل کریں یا نتیجہ کو State فیلڈ میں کیش کریں۔
تیسری غلطی super.initState() اور super.dispose() کو نہ بلانا ہے۔ ان طریقوں کو اوور رائڈ کرتے وقت، ڈویلپر کو والدین کے نفاذ کو بلانا ہوگا۔ ایسا نہ کرنے پر فریم ورک Element حالت کو صحیح طریقے سے منظم نہیں کر سکے گا، جس سے ٹریک کرنے میں مشکل بگ پیدا ہوتے ہیں۔
mounted چیک کریںsuper.initState() اور super.dispose() بلانا نہ بھولیںاکثر پوچھے گئے سوالات
StatefulWidget setState کے ذریعے اپنی حالت تبدیل کر سکتا ہے، اس کا ایک لائف سائیکل (initState، dispose) ہے اور ایک علیحدہ State آبجیکٹ بناتا ہے۔ StatelessWidget حالت تبدیل نہیں کر سکتا اور اس کے پاس لائف سائیکل طریقے نہیں ہیں — یہ صرف منتقل کردہ ڈیٹا ظاہر کرتا ہے۔
createState ہر StatefulElement انسٹنس کے لیے ٹھیک ایک بار بلایا جاتا ہے۔ چاہے والدین کئی بار دوبارہ تعمیر کریں، جب تک ویجٹ کی قسم اور Key تبدیل نہیں ہوتے، createState نہیں بلایا جاتا — موجودہ State آبجیکٹ استعمال ہوتا ہے۔
وسائل آزاد نہیں ہوں گے: کنٹرولرز پس منظر میں کام کرتے رہیں گے، سٹریم سبسکرپشنز فعال رہیں گی، ٹائمر منسوخ نہیں ہوں گے۔ یہ میموری لیک کا باعث بنتا ہے اور dispose کے بعد setState کالز کا سبب بن سکتا ہے، جو استثنا پھینکتی ہے۔
ہاں، StatefulWidget کا کنسٹرکٹر const ہو سکتا ہے۔ تاہم، یہ StatelessWidget جتنا فائدہ نہیں دیتا — State آبجیکٹ پہلی بار داخل کرنے پر بھی بنایا جائے گا۔ const صرف ویجٹ کو متاثر کرتا ہے (ہلکا ریپر)، State کو نہیں۔
didUpdateWidget اس وقت بلایا جاتا ہے جب والدین نئے پیرامیٹرز کے ساتھ StatefulWidget منتقل کرتے ہیں۔ یہ حالت کو نئے ڈیٹا کے ساتھ ہم آہنگ کرنے کے لیے ضروری ہے — مثال کے طور پر، اگر پیرامیٹرز میں userId تبدیل ہو گیا ہے، تو نئے صارف کا پروفائل لوڈ کرنا ہوگا۔
خلاصہ
ہم ایک موبائل ایپلیکیشن ٹرنکی تیار کریں گے
IT Sectr 2017 سے اسٹارٹ اپس اور کاروبار کے لیے iOS اور Android ایپلیکیشنز بناتا ہے۔ ہم آپ کو مشورہ دیں گے اور بہترین حل تجویز کریں گے۔
مزید پڑھیں