تخطَّ إلى المحتوى
ARAB CODEمجتمع المطورين العرب

أساسيات إدارة الحالة في تطبيقات الجوال: محلية أم مشتركة، ومتى تحتاج مكتبة

درسنُشر ٢٤ أكتوبر ٢٠٢٦ · 0 رد · 1 مشاهدة#إدارة-الحالة#flutter#riverpod#تطبيقات
قبل ساعتين

مقدمة

«الحالة» هي أي بيانات قد تتغير وتؤثر في ما يُعرض: نص في حقل، قائمة مواضيع، هل المستخدم مسجل الدخول. معظم أخطاء الواجهات سببها حالة في المكان الخطأ: مكررة في موضعين فتتناقض، أو مخفية داخل عنصر يحتاجها غيره. قبل اختيار مكتبة، افهم أنواع الحالة.

أهداف التعلم

  • التمييز بين الحالة المؤقتة (Ephemeral) وحالة التطبيق.
  • رفع الحالة (Lifting state up) إلى أقرب أب مشترك.
  • تمثيل الحالة غير المتزامنة (تحميل/نجاح/خطأ).
  • معرفة متى تحتاج مكتبة مثل Riverpod أو Bloc.

1. الحالة المؤقتة: ابقها محلية

ما إذا كانت قائمة منسدلة مفتوحة، أو موضع التبويب الحالي — لا يهم أي جزء آخر من التطبيق. StatefulWidget كافٍ تماماً:

class LikeButton extends StatefulWidget {
  const LikeButton({super.key});
  @override
  State<LikeButton> createState() => _LikeButtonState();
}

class _LikeButtonState extends State<LikeButton> {
  bool liked = false;
  @override
  Widget build(BuildContext context) => IconButton(
        icon: Icon(liked ? Icons.favorite : Icons.favorite_border),
        onPressed: () => setState(() => liked = !liked),
      );
}

(في تطبيق حقيقي حالة الإعجاب تُحفظ على الخادم، فهي ليست مؤقتة — وهذا بالضبط سؤال التصنيف.)

2. رفع الحالة

إذا احتاج عنصران الحالة نفسها، انقلها إلى أقرب أب مشترك ومررها للأسفل مع دوال التغيير. مثال: عداد السلة في الشريط العلوي وزر «أضف للسلة» في الصفحة يحتاجان الحالة نفسها.

3. الحالة غير المتزامنة: ثلاث حالات دائماً

كل بيانات من الشبكة لها ثلاث حالات على الأقل: تحميل، نجاح، خطأ. مثّلها صراحة:

sealed class LoadState<T> {}
class Loading<T> extends LoadState<T> {}
class Loaded<T> extends LoadState<T> { Loaded(this.data); final T data; }
class Failed<T> extends LoadState<T> { Failed(this.message); final String message; }
Widget build(BuildContext context) => switch (state) {
      Loading() => const Center(child: CircularProgressIndicator()),
      Loaded(:final data) => TopicList(topics: data),
      Failed(:final message) => ErrorView(message: message, onRetry: reload),
    };

sealed يجعل المترجم يحذرك إن نسيت حالة.

4. حالة التطبيق مع Riverpod

حين تتشارك شاشات كثيرة حالة (المستخدم الحالي، الإعدادات، بيانات مخزنة مؤقتاً)، تحتاج مكاناً واحداً لها:

final topicsProvider = FutureProvider<List<Topic>>((ref) async {
  final repo = ref.watch(topicsRepositoryProvider);
  return repo.latest();
});

class TopicsPage extends ConsumerWidget {
  const TopicsPage({super.key});
  @override
  Widget build(BuildContext context, WidgetRef ref) {
    final topics = ref.watch(topicsProvider);
    return topics.when(
      loading: () => const CircularProgressIndicator(),
      error: (e, _) => ErrorView(message: 'تعذر التحميل', onRetry: () => ref.invalidate(topicsProvider)),
      data: (list) => TopicList(topics: list),
    );
  }
}

نفس المبدأ في Jetpack Compose: remember للحالة المحلية، وViewModel مع StateFlow لحالة الشاشة.

5. متى تحتاج مكتبة؟

  • تطبيق صغير بشاشات قليلة: setState ورفع الحالة يكفيان.
  • حالة مشتركة بين شاشات كثيرة، أو تخزين مؤقت، أو اختبارات للمنطق: مكتبة مثل Riverpod أو Bloc توفر عليك الكثير.
  • لا تختر المكتبة لأنها «رائجة»؛ اختر واحدة واثبت عليها في المشروع.

تمرين عملي

  1. ابنِ شاشة قائمة مواضيع بالحالات الثلاث (تحميل/نجاح/خطأ) مع زر إعادة المحاولة.
  2. أضف شارة عدد في الشريط العلوي تعتمد على الحالة نفسها، وارفع الحالة حتى تتزامن.
  3. اكتب اختباراً يحاكي فشل المستودع ويتأكد من ظهور زر إعادة المحاولة.

أخطاء شائعة

  • نسخ الحالة نفسها في مكانين فتتعارض.
  • حالة مشتركة على مستوى التطبيق لأشياء مؤقتة (تضخم وإعادة رسم غير لازمة).
  • تجاهل حالة الخطأ وترك المستخدم أمام مؤشر تحميل لا ينتهي.
  • تعديل كائن الحالة مباشرة بدل إنشاء نسخة جديدة، فلا يُعاد الرسم.

الخلاصة

صنّف الحالة أولاً: مؤقتة تبقى محلية، ومشتركة تُرفع أو توضع في مخزن واحد. مثّل البيانات غير المتزامنة بحالاتها الثلاث صراحة، واختر المكتبة على قدر الحاجة.

مصادر مقترحة

  • توثيق Flutter: «State management» و«Differentiate between ephemeral state and app state».
  • توثيق Riverpod الرسمي.
  • Android Developers: «State and Jetpack Compose».

الرد على الموضوع

سجّل الدخول للمشاركة في النقاش.

نقاشات مشابهة