تكرار السؤال: …
الإجابة المختصرة
الـ Widget هو توصيف تصريحي ثابت خفيف وغير قابل للتعديل (Immutable Configuration)، والـ Element يدير الهوية وشجرة البناء وموقع الحالة في الذاكرة، والـ RenderObject يتولى حساب الحجم والـ Layout والرسم واللمس الفعلي على الشاشة.
الشرح
عند تشغيل التطبيق، يُنشئ كل Widget عنصراً نظيراً Element عبر createElement(). يحتفظ الـ Element بمرجع للـ Widget والـ RenderObject. عندما يتغير الـ Widget أثناء الـ Rebuild، يتحقق الـ Element عبر دالة Widget.canUpdate() من مطابقة runtimeType والـ Key. إذا تطابقا، يقوم الـ Element بتحديث مرجعه فقط وتحديث خصائص الـ RenderObject دون إعادة بناء الشجرة من الصفر، محققاً سرعة فائقة في الأداء (O(N) reconciliation).
مثال بالكود
// The rule Flutter uses to decide whether an existing Element can be reused for a new Widget
bool canUpdate(Widget oldWidget, Widget newWidget) {
return oldWidget.runtimeType == newWidget.runtimeType && oldWidget.key == newWidget.key;
}
// Peek at the three trees for one widget at runtime
class Probe extends StatelessWidget {
const Probe({super.key});
@override
Widget build(BuildContext context) {
final element = context as Element; // Element tree
final render = context.findRenderObject(); // RenderObject tree (null before the first layout)
debugPrint('$runtimeType -> ${element.runtimeType} -> ${render?.runtimeType}');
return const SizedBox();
}
}أخطاء شائعة
- الاعتقاد بأن إنشاء كائنات Widget جديدة مع كل build مكلف للذاكرة، متجاهلين أن الـ Widgets خفيفة جداً ويتم تدميرها وجمعها فورياً بواسطة Dart Garbage Collector بينما تبقى كائنات الـ Elements والـ RenderObjects حية.