State Management في Flutter: Provider، Riverpod، BLoC
تطوير التطبيقات

State Management في Flutter: Provider، Riverpod، BLoC

إدارة الحالة أكبر تحدٍّ في تطبيقات Flutter. قارن بين أشهر 3 حلول واختر الأنسب لمشروعك.

م
مؤسس LahbabiGuide
3 دقائق قراءة
شارك:

لماذا State Management ضروري؟

في تطبيق بسيط (عدّاد)، setState يكفي. لكن حين يكبر التطبيق:

  • البيانات تتنقّل بين شاشات
  • نفس البيانات تُستخدم في أماكن كثيرة
  • تحديث واحد يجب أن يظهر في عدّة widgets

هنا تحتاج state management صحيح.

الخيارات الثلاثة الأشهر

1. Provider — الرسمي القديم

الحلّ الذي كان يوصي به فريق Flutter. بسيط، مناسب للمشاريع الصغيرة والمتوسّطة.

bash
flutter pub add provider

2. Riverpod — خليفة Provider

نفس مؤلّف Provider، لكن أقوى وأكثر أماناً. الخيار المفضّل حالياً.

bash
flutter pub add flutter_riverpod

3. BLoC — للمشاريع الكبيرة

Business Logic Component. نمط أقوى لفصل المنطق عن الواجهة، شائع في تطبيقات الشركات.

bash
flutter pub add flutter_bloc

مثال: عدّاد بـ Provider

النموذج

dart
import 'package:flutter/foundation.dart';

class Counter extends ChangeNotifier {
  int _count = 0;
  int get count => _count;

  void increment() {
    _count++;
    notifyListeners(); // يُخبر المستمعين
  }
}

التوفير للتطبيق

dart
void main() {
  runApp(
    ChangeNotifierProvider(
      create: (_) => Counter(),
      child: const MyApp(),
    ),
  );
}

الاستهلاك

dart
class CounterView extends StatelessWidget {
  const CounterView({super.key});

  @override
  Widget build(BuildContext context) {
    final counter = context.watch<Counter>();
    return Column(
      children: [
        Text('${counter.count}'),
        ElevatedButton(
          onPressed: () => context.read<Counter>().increment(),
          child: const Text('+1'),
        ),
      ],
    );
  }
}
إعلان

نفس المثال بـ Riverpod

dart
// تعريف الـ provider
final counterProvider = StateProvider<int>((ref) => 0);

// التطبيق (لفّ الـ root)
void main() {
  runApp(const ProviderScope(child: MyApp()));
}

// الاستهلاك
class CounterView extends ConsumerWidget {
  const CounterView({super.key});

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    final count = ref.watch(counterProvider);
    return Column(
      children: [
        Text('$count'),
        ElevatedButton(
          onPressed: () => ref.read(counterProvider.notifier).state++,
          child: const Text('+1'),
        ),
      ],
    );
  }
}

نفس المثال بـ BLoC

Events و States

dart
// الأحداث
abstract class CounterEvent {}
class Increment extends CounterEvent {}
class Decrement extends CounterEvent {}

// الـ Bloc
class CounterBloc extends Bloc<CounterEvent, int> {
  CounterBloc() : super(0) {
    on<Increment>((event, emit) => emit(state + 1));
    on<Decrement>((event, emit) => emit(state - 1));
  }
}

الاستخدام

dart
void main() {
  runApp(
    BlocProvider(
      create: (_) => CounterBloc(),
      child: const MyApp(),
    ),
  );
}

// الواجهة
BlocBuilder<CounterBloc, int>(
  builder: (context, count) => Text('$count'),
)

// الأحداث
ElevatedButton(
  onPressed: () => context.read<CounterBloc>().add(Increment()),
  child: const Text('+1'),
)

مقارنة

| المعيار | Provider | Riverpod | BLoC | |---------|----------|----------|------| | منحنى التعلّم | سهل | متوسّط | شديد | | Boilerplate | قليل | قليل | كثير | | أمان النوع | متوسّط | ممتاز | ممتاز | | Testing | جيّد | ممتاز | ممتاز | | مناسب لـ | مشاريع صغيرة | كل شيء | مشاريع كبيرة/فِرَق |

التوصية

  • مشروع جديد: Riverpod
  • مشروع فيه Provider: استمرّ بـ Provider حتى يكبر فعلاً
  • شركة كبيرة + فريق: BLoC
  • setState كافٍ لعدّاد بسيط — لا تعقّد الأمور بلا حاجة

أخطاء شائعة

  • تعديل الـ state مباشرة بدون notifyListeners
  • watch في build خارج الـ context
  • وضع كل الـ state في Provider واحد ضخم — قسّم لعدّة providers صغيرة

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

هل أستخدم GetX؟

GetX شائع في العالم العربي لكنه غير موصى به من مجتمع Flutter الرسمي. يخلط state + routing + DI بطريقة غير Flutter-idiomatic. تجنّبه في المشاريع الجدّية.

متى أحتاج state management أصلاً؟

إن لديك أكثر من 3-4 شاشات تشترك في بيانات. لشاشة واحدة، setState كافٍ.

اقرأ أيضاً

مقالات ذات صلة