Flutter BuildContext بعد await: الحل الصحيح

x32x01
  • بواسطة x32x01 ||
  • #1
لو ظهر لك في Flutter تحذير عن استخدام BuildContext بعد await، فالمشكلة مش في BuildContext نفسه.

المشكلة إن الكود ممكن ينتظر عملية غير متزامنة، وخلال فترة الانتظار تكون الـ Widget اتشالت من الشاشة. لو استخدمت BuildContext بعدها، ممكن تحاول تتعامل مع Widget لم تعد موجودة.

الحل ببساطة هو التأكد إن الـ Widget ما زالت موجودة قبل استخدام الـ BuildContext.



إيه اللي بيحصل بعد await؟​

لما تكتب:
Code:
await someAsyncOperation();
التنفيذ بيتوقف مؤقتًا لحد ما العملية تخلص.
وخلال الوقت ده، المستخدم ممكن ينتقل لشاشة تانية، أو الـ Widget الحالية يتم حذفها من شجرة الـ Widget.
بعد انتهاء العملية، الكود الموجود بعد await هيكمل التنفيذ.
مثلًا:
Code:
Future loadData() async {
await Future.delayed(const Duration(seconds: 2));

Navigator.of(context).pop();
}
هنا فيه احتمال إن الـ Widget اللي كان مرتبط بيها context تكون اتشالت قبل انتهاء الثانيتين.
في الحالة دي، استخدام context بعد await ممكن يكون غير آمن.



ليه Flutter بتطلع التحذير؟​

Flutter عندها lint اسمه use_build_context_synchronously، وهدفه تنبيهك لما تستخدم BuildContext بعد عملية غير متزامنة.
الفكرة الأساسية:
بعد await، حالة الـ Widget ممكن تكون اتغيرت.
لذلك لا تفترض إن الـ BuildContext ما زال صالحًا لمجرد إنك كنت تستخدمه قبل await.



الحل باستخدام mounted​

لو أنت داخل State، تقدر تتأكد إن الـ Widget ما زالت موجودة باستخدام mounted:
Code:
Future loadData() async {
await Future.delayed(const Duration(seconds: 2));

if (!mounted) return;

Navigator.of(context).pop();
}
لو الـ Widget اتشالت أثناء الانتظار، هتكون قيمة mounted هي false، وبالتالي الكود هيتوقف قبل استخدام context.



الحل باستخدام context.mounted​

في الحالات اللي عندك فيها BuildContext مباشرة، ممكن تستخدم context.mounted:
Code:
Future showMessage(BuildContext context) async {
await Future.delayed(const Duration(seconds: 2));

if (!context.mounted) return;

ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
content: Text('تم تحميل البيانات'),
),
);
}
وده مفيد خصوصًا لما تكون الدالة بتستقبل BuildContext كـ parameter.



مثال عملي مع زر​

مثلًا لو عندك زر بيبدأ عملية تحميل وبعدها ينتقل لشاشة تانية:
Code:
ElevatedButton(
onPressed: () async {
await loadData();

if (!context.mounted) return;<br><br>Navigator.of(context).push(<br>  MaterialPageRoute(<br>    builder: (_) =&gt; const NextPage(),<br>  ),<br>);<br>
},
child: const Text('Continue'),
)
هنا التأكد من context.mounted بيضمن إن الـ Widget المرتبطة بالـ context ما زالت موجودة قبل تنفيذ عملية التنقل.



هل لازم أستخدم mounted بعد كل await؟​

مش معنى وجود await إنك لازم تستخدم mounted في كل مرة.
المهم هو الحالة اللي بيتم فيها استخدام BuildContext بعد العملية غير المتزامنة.
لو الكود بعد await لا يستخدم BuildContext أو أي شيء مرتبط بدورة حياة الـ Widget، فغالبًا لا تحتاج لهذا الفحص.
مثلًا:
Code:
Future calculateValue() async {
await Future.delayed(const Duration(seconds: 1));

return 100;
}
هنا مفيش استخدام لـ context بعد await، لذلك مشكلة BuildContext غير موجودة في هذا المثال.



خطأ شائع​

من الأخطاء الشائعة إنك تخفي التحذير بدل ما تعالج السبب.
مثلًا استخدام // ignore لمجرد إسكات الـ lint مش هو الحل الأفضل.
الأفضل إنك تسأل نفسك:
هل الـ Widget ممكن تكون اتشالت أثناء فترة الـ await؟
لو الإجابة نعم، اعمل فحص مناسب باستخدام mounted أو context.mounted قبل استخدام BuildContext.



الخلاصة​

تحذير Flutter من استخدام BuildContext بعد await موجود لأن الـ Widget ممكن تكون اتشالت أثناء انتظار العملية غير المتزامنة.
الحل المعتاد هو:
Code:
if (!mounted) return;
داخل State، أو:
Code:
if (!context.mounted) return;
عندما يكون لديك BuildContext مباشر.
الفكرة ببساطة: ما تستخدمش الـ BuildContext بعد عملية غير متزامنة إلا بعد التأكد إن الـ Widget ما زالت موجودة.
يمكنك أيضًا مشاهدة شرح سريع للفكرة في الفيديو القصير المرتبط بالموضوع.
Video thumbnail


الأسئلة الشائعة​

--------------

ما هو سبب تحذير use_build_context_synchronously؟​

التحذير يظهر عندما يتم استخدام BuildContext بعد await، لأن الـ Widget المرتبطة بهذا الـ context قد تكون أُزيلت أثناء انتظار العملية غير المتزامنة.

هل mounted يحل مشكلة BuildContext بعد await؟​

نعم، عندما تكون داخل State، يمكنك فحص mounted قبل استخدام context بعد await.

ما الفرق بين mounted و context.mounted؟​

mounted هي خاصية متاحة داخل State، بينما context.mounted تسمح لك بالتحقق من صلاحية الـ BuildContext نفسه.

هل يمكن تجاهل تحذير use_build_context_synchronously؟​

يمكن إسكات تحذير الـ lint، لكن الأفضل عادةً معالجة السبب والتأكد من أن الـ Widget أو الـ BuildContext ما زال صالحًا قبل استخدامه بعد await.
 
مواضيع مشابهة
x32x01
الردود
0
المشاهدات
37
x32x01
x32x01
x32x01
الردود
0
المشاهدات
35
x32x01
x32x01
x32x01
الردود
0
المشاهدات
30
x32x01
x32x01
x32x01
الردود
0
المشاهدات
32
x32x01
x32x01
x32x01
الردود
0
المشاهدات
42
x32x01
x32x01
إحصائيات المنتدى
المواضيع
2,293
المشاركات
2,358
الأعضاء
16
آخر عضو مسجل
HcN57
عودة
أعلى