GetX: المفاهيم الأساسية، التنقل وحقن التبعيات في Flutter

المؤلف: IT Sectr نُشر: 2026-02-19 وقت القراءة: 7 دق

GetX — إطار عمل مصغر خفيف لـ Flutter يجمع بين إدارة الحالة والتنقل وحقن التبعيات في حزمة واحدة. تم تطويره بواسطة أمير حسين عبد الرشيدي، ويقدم GetX حدًا أدنى من الكود التمهيدي: بدون Stream، بدون ChangeNotifier، بدون BuildContext للتنقل. وفقًا لـ pub.dev، حصل GetX على أكثر من 13 ألف إعجاب، ليصبح واحدًا من أشهر حزم Flutter.

النقاط الرئيسية

  • Obx — واجهة تفاعلية تعيد البناء عند تغير متغير Rx
  • GetController — فئة منطق الأعمال مع دوال ومتغيرات Rx
  • Get.to — تنقل بدون BuildContext عبر مسارات مسماة
  • Get.put / Get.find — حقن واسترجاع التبعيات عبر حاوية DI
  • متغيرات Rx — أغلفة تفاعلية (RxInt, RxString, RxBool) مع إشعار تلقائي

ما هو GetX؟

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 و Rx

Obx — واجهة GetX تفاعلية تعيد البناء عندما تتغير متغيرات Rx. لا يتطلب Obx اشتراكًا أو dispose أو دوال Builder — ببساطة لف الواجهة في Obx واستخدم متغير Rx داخله. يتتبع Obx تلقائيًا متغيرات Rx المستخدمة ويعيد الرسم فقط عند تغيرها.

Dart
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 للواجهات المعقدة ذات التبعيات المتعددة.

GetController ودورة الحياة

GetxController — فئة أساسية لمنطق الأعمال مع دعم دورة الحياة. يحتوي GetxController على دوال: onInit() (التهيئة)، onReady() (بعد الإطار الأول)، onClose() (تنظيف الموارد). على عكس ChangeNotifier و StateNotifier، يدير GetxController الاشتراكات تلقائيًا: عند تدمير الصفحة، يتم إلغاء اشتراك جميع متغيرات Rx و Workers.

Dart
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.

Dart
// تنقل عادي
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 فقط عند فتح الشاشة.

حقن التبعيات مع GetX

Get.put — يسجل مثيلًا في حاوية DI. Get.find — يسترجع مثيلًا من الحاوية. Get.lazyPut — تهيئة بطيئة (يُُنشأ عند أول استدعاء find). Get.putAsync — تهيئة غير متزامنة (للخدمات ذات init). Get.delete — يحذف من الحاوية (يُستدعى تلقائيًا بواسطة Bindings عند تدمير المسار).

الدالةمتى تُنشأمتى تُحذف
Get.putفورًاGet.delete أو onClose
Get.lazyPutعند أول findGet.delete أو onClose
Get.putAsyncبعد اكتمال FutureGet.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: أفضل الممارسات والأداء

أداء 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 عن Provider؟

GetX — إطار عمل مصغر مع DI خاص به وتنقل وتفاعلية Rx. Provider — فقط إدارة الحالة عبر ChangeNotifier و InheritedWidget. لا يتطلب GetX BuildContext، ولديه تنقل و DI مدمجان، ويقلل الكود التمهيدي بنسبة 60-70%. يستخدم Provider Navigator القياسي لـ Flutter ويتطلب حلولًا خارجية لـ DI. GetX أسرع في التطوير، Provider أقرب إلى API Flutter الأصلي.

ما هي Workers في GetX؟

Workers — أدوات للمعالجة التفاعلية لتغيرات متغيرات Rx. ever — استدعاء عند كل تغيير، once — فقط عند التغيير الأول، debounce — بتأخير (لحقول البحث)، interval — ليس أكثر من N مرة (للتحليلات). تُعلن Workers في onInit() في GetxController وتلغي اشتراكها تلقائيًا في onClose(). هذا يستبدل addListener/removeListener اليدوي مع ChangeNotifier.

كيف تختبر GetX؟

يوفر 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 للمشاريع الكبيرة؟

GetX مناسب للمشاريع من أي حجم لكنه يتطلب انضباطًا. للمشاريع الكبيرة (10+ شاشات)، استخدم: Bindings لعزل Controller، وحدات (ملفات GetPages لكل ميزة)، GetView بدلاً من Get.find اليدوي في build. الخطر الرئيسي هو إساءة استخدام الوصول العام (Get.find في أي مكان). مراجعات الكود الصارمة والأدلة المعمارية تحل هذه المشكلة. العديد من تطبيقات الإنتاج بملايين المستخدمين تعمل على GetX.

ما هي Bindings في GetX؟

Bindings — فئة تربط المسار بتبعياته. عند دخول شاشة، ينشئ Binding Controller والخدمات عبر Get.lazyPut، ويحذفها عند الخروج. تنفذ Bindings التهيئة البطيئة: Controller غير موجود في الذاكرة حتى يتم فتح الشاشة. هذا يوفر RAM ووقت بدء التطبيق. تُعلن في GetPage: GetPage(name: '/profile', page: () => ProfileScreen(), binding: ProfileBinding()).

الخلاصة

  • GetX — إطار عمل مصغر لـ Flutter مع إدارة الحالة والتنقل و DI في حزمة واحدة
  • Obx و Rx — أغلفة تفاعلية مع إعادة رسم تلقائية بدون Stream و ChangeNotifier
  • GetxController — فئة منطق الأعمال مع دورة حياة onInit/onReady/onClose
  • Get.to / Get.back — تنقل بدون BuildContext مع رسوم متحركة مدمجة
  • Get.put / Get.find — حاوية DI بدون شجرة Provider مع تهيئة بطيئة
  • Workers — ever، once، debounce، interval للمعالجة التفاعلية للتغيرات
  • Bindings — تهيئة بطيئة لـ Controller عند فتح مسار مع تدمير تلقائي

سنقوم بتطوير تطبيق جوال جاهز

تقدم IT Sectr تطبيقات iOS وAndroid للشركات الناشئة والشركات منذ عام 2017. سوف نقدم لك النصح ونقترح أفضل حل.

مناقشة المشروع

اقرأ أيضًا