GetX — إطار عمل مصغر خفيف لـ Flutter يجمع بين إدارة الحالة والتنقل وحقن التبعيات في حزمة واحدة. تم تطويره بواسطة أمير حسين عبد الرشيدي، ويقدم GetX حدًا أدنى من الكود التمهيدي: بدون Stream، بدون ChangeNotifier، بدون BuildContext للتنقل. وفقًا لـ pub.dev، حصل GetX على أكثر من 13 ألف إعجاب، ليصبح واحدًا من أشهر حزم Flutter.
النقاط الرئيسية
GetX — إطار عمل مصغر شامل لـ Flutter يحل ثلاث مهام رئيسية في التطوير: إدارة الحالة والتنقل (التوجيه) وحقن التبعيات (DI). لا يتطلب GetX Stream أو ChangeNotifier أو Builders أو اشتراكات — يتم توفير كل التفاعلية بواسطة أغلفة Rx القائمة على GetValue و GetStream، والتي تعمل أسرع بعشرات المرات من ChangeNotifier.
يتم وضع GetX كبديل لمجموعة Provider + Navigator + get_it/kiwi. بدلاً من تثبيت ثلاث حزم مختلفة وكتابة 10 أسطر من الإعدادات، يقدم GetX كل شيء جاهزًا بسطر واحد: GetMaterialApp بدلاً من MaterialApp. يعمل التنقل عبر Get.to(NextScreen()) بدون BuildContext، وحقن التبعيات عبر Get.put(Service()) بدون شجرة Provider.
وفقًا لـ استطلاع مجتمع Flutter 2025، يُستخدم GetX في 43% من مشاريع Flutter. الأسباب الرئيسية لاختياره: حد أدنى للدخول (5 دقائق للتعلم)، بدون كود تمهيدي (ينخفض الكود بنسبة 60-70% مقارنة بـ Provider أو BLoC)، وتطوير MVP سريع. ينتقد البعض انتهاك مبدأ فصل المسؤوليات وصعوبة التصحيح.
Obx — واجهة GetX تفاعلية تعيد البناء عندما تتغير متغيرات Rx. لا يتطلب Obx اشتراكًا أو dispose أو دوال Builder — ببساطة لف الواجهة في Obx واستخدم متغير Rx داخله. يتتبع Obx تلقائيًا متغيرات Rx المستخدمة ويعيد الرسم فقط عند تغيرها.
class CounterController extends GetxController {
final count = 0.obs;
void increment() => count++;
}
class CounterScreen extends StatelessWidget {
final controller = Get.put(CounterController());
@override
Widget build(context) => Obx(() => Text('${controller.count}'));
}متغيرات Rx: .obs — getter يلف أي قيمة في كائن Rx. يوفر GetX فئات Rx مقيدة: RxInt، RxString، RxDouble، RxBool، RxList، RxMap. تتصرف جميع متغيرات Rx مثل البدائيات العادية: count++، name.value = 'Hello'، items.add(item). التغيير يُبلغ تلقائيًا مشتركي Obx.
GetBuilder — بديل لـ Obx بدون Rx، يعمل عبر استدعاء يدوي لـ update(). GetBuilder.filter — للتحديث الموجه بمفاتيح ID. Obx أسرع (تتبع تلقائي للتبعيات)، GetBuilder أكثر قابلية للتنبؤ (استدعاء تحديث صريح). يُوصى بـ Obx للسيناريوهات البسيطة و GetBuilder للواجهات المعقدة ذات التبعيات المتعددة.
GetxController — فئة أساسية لمنطق الأعمال مع دعم دورة الحياة. يحتوي GetxController على دوال: onInit() (التهيئة)، onReady() (بعد الإطار الأول)، onClose() (تنظيف الموارد). على عكس ChangeNotifier و StateNotifier، يدير GetxController الاشتراكات تلقائيًا: عند تدمير الصفحة، يتم إلغاء اشتراك جميع متغيرات Rx و Workers.
class AuthController extends GetxController {
final user = Rx<User?>(null);
final isLoading = false.obs;
@override
void onInit() {
ever(isLoading, (_) => print('Loading: $isLoading'));
super.onInit();
}
Future<void> login(String email, String password) async {
isLoading.value = true;
user.value = await api.login(email, password);
isLoading.value = false;
}
}Workers — أدوات تفاعلية لـ GetX: ever (يُستدعى عند كل تغيير)، once (فقط عند التغيير الأول)، debounce (بتأخير)، interval (ليس أكثر من N مرة في الثانية). تحل Workers مهامًا نموذجية: التحقق من الحقول (debounce)، التحليلات (once)، المزامنة (ever). تلغي Workers اشتراكها تلقائيًا عند استدعاء onClose()، مما يمنع تسرب الذاكرة.
تنقل GetX لا يتطلب BuildContext للانتقال بين الشاشات. بدلاً من Navigator.push(context, MaterialPageRoute(...))، يُستخدم Get.to(NextScreen()) — قابل للاستدعاء من أي مكان، بما في ذلك Controller بدون الوصول إلى BuildContext. يدعم GetX المسارات المسماة والرسوم المتحركة والوسائط وتمرير الوسائط بدون MaterialPageRoute.
// تنقل عادي
Get.to(ProfileScreen());
Get.back();
Get.off(LoginScreen()); // استبدال المسار الحالي
Get.offAll(HomeScreen()); // مسح المكدس
// مسارات مسماة
Get.toNamed('/profile', arguments: 'user123');
Get.offNamed('/login');
// Middleware
GetPage(
name: '/profile',
page: () => ProfileScreen(),
middlewares: [AuthMiddleware()],
)GetPage و GetPages: يستخدم GetX GetPages بدلاً من المسارات في MaterialApp. Middleware — فحوصات المصادقة وإعادة التوجيه والتحليلات قبل دخول الشاشة. Transition — رسوم متحركة مدمجة للانتقال: fadeIn، zoom، leftToRight، topToBottom. Bindings — فئة تهيئ Controller والتبعيات عند دخول المسار. تحل Bindings مشكلة التهيئة البطيئة: يتم إنشاء Controller فقط عند فتح الشاشة.
Get.put — يسجل مثيلًا في حاوية DI. Get.find — يسترجع مثيلًا من الحاوية. Get.lazyPut — تهيئة بطيئة (يُُنشأ عند أول استدعاء find). Get.putAsync — تهيئة غير متزامنة (للخدمات ذات init). Get.delete — يحذف من الحاوية (يُستدعى تلقائيًا بواسطة Bindings عند تدمير المسار).
| الدالة | متى تُنشأ | متى تُحذف |
|---|---|---|
| Get.put | فورًا | Get.delete أو onClose |
| Get.lazyPut | عند أول find | Get.delete أو onClose |
| Get.putAsync | بعد اكتمال Future | Get.delete أو onClose |
| Get.create | في كل find (مصنع جديد) | لا |
DI في GetX — أبسط حاوية DI في Flutter. لا شجرة Provider، لا Module، لا Scope. Get.put(Repository()) في Controller أو main.dart يجعل الكائن متاحًا في أي مكان في التطبيق عبر Get.find<Repository>(). يدعم DI في GetX أيضًا الوسم (tag: 'api') و الديمومة (permanent: true) لمنع الحذف.
أداء GetX يعتمد على أغلفة Rx التي تعمل عبر GetStream — تنفيذ مخصص لـ Stream محسّن لـ Flutter. وفقًا لاختبارات الأداء لـ GetX، متغيرات Rx أسرع 2-3 مرات من ChangeNotifier وأسرع 5-7 مرات من BLoC مع التحديثات المتكررة (30+ إطارًا في الثانية). لا يستخدم GetX BuildContext للاشتراكات، مما يلغي إعادة بناء شجرة الواجهات أثناء التنقل.
أفضل الممارسات: استخدم GetBuilder بدلاً من Obx للواجهات ذات العناصر الفرعية المتعددة (قوائم، جداول). قسم Controller إلى وحدات وظيفية بدلاً من Controller واحد ضخم لكل صفحة. استخدم Bindings لتهيئة Controller، وليس Get.put في دالة build. GetView — StatelessWidget مختصر مع الوصول إلى Controller عبر controller بدون Get.find.
القيود المعروفة: يستخدم GetX متغيرات عامة (Get.find، Get.to)، مما قد يعقد الاختبار. يتطلب إنشاء تبعيات وهمية عبر GetX استخدام Get.replace() أو Get.reset() بين الاختبارات. للعزل، يُوصى باستخدام Get.testMode = true. لا يُوصى بـ GetX للتطبيقات التي تتطلب بنية صارمة بحدود طبقات واضحة — في هذه الحالة، BLoC أو Riverpod مع توليد الكود هو الأفضل.
الأسئلة الشائعة
GetX — إطار عمل مصغر مع DI خاص به وتنقل وتفاعلية Rx. Provider — فقط إدارة الحالة عبر ChangeNotifier و InheritedWidget. لا يتطلب GetX BuildContext، ولديه تنقل و DI مدمجان، ويقلل الكود التمهيدي بنسبة 60-70%. يستخدم Provider Navigator القياسي لـ Flutter ويتطلب حلولًا خارجية لـ DI. GetX أسرع في التطوير، Provider أقرب إلى API Flutter الأصلي.
Workers — أدوات للمعالجة التفاعلية لتغيرات متغيرات Rx. ever — استدعاء عند كل تغيير، once — فقط عند التغيير الأول، debounce — بتأخير (لحقول البحث)، interval — ليس أكثر من N مرة (للتحليلات). تُعلن Workers في onInit() في GetxController وتلغي اشتراكها تلقائيًا في onClose(). هذا يستبدل addListener/removeListener اليدوي مع ChangeNotifier.
يوفر GetX Get.testMode = true لتفعيل وضع الاختبار. تُستبدل التبعيات عبر Get.replace<Service>(mockService). بين الاختبارات، يُستدعى Get.reset() لتنظيف حاوية DI. تُختبر Controller مباشرة بدون Flutter: final c = CounterController(); c.increment(); expect(c.count.value, 1). للواجهات مع Obx، استخدم tester.pumpWidget مع InjectMocker.
GetX مناسب للمشاريع من أي حجم لكنه يتطلب انضباطًا. للمشاريع الكبيرة (10+ شاشات)، استخدم: Bindings لعزل Controller، وحدات (ملفات GetPages لكل ميزة)، GetView بدلاً من Get.find اليدوي في build. الخطر الرئيسي هو إساءة استخدام الوصول العام (Get.find في أي مكان). مراجعات الكود الصارمة والأدلة المعمارية تحل هذه المشكلة. العديد من تطبيقات الإنتاج بملايين المستخدمين تعمل على GetX.
Bindings — فئة تربط المسار بتبعياته. عند دخول شاشة، ينشئ Binding Controller والخدمات عبر Get.lazyPut، ويحذفها عند الخروج. تنفذ Bindings التهيئة البطيئة: Controller غير موجود في الذاكرة حتى يتم فتح الشاشة. هذا يوفر RAM ووقت بدء التطبيق. تُعلن في GetPage: GetPage(name: '/profile', page: () => ProfileScreen(), binding: ProfileBinding()).
الخلاصة
سنقوم بتطوير تطبيق جوال جاهز
تقدم IT Sectr تطبيقات iOS وAndroid للشركات الناشئة والشركات منذ عام 2017. سوف نقدم لك النصح ونقترح أفضل حل.