Riverpod — إدارة التبعيات المُجمَّعة لتطبيقات Flutter

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

Riverpod — مدير حالة وتبعيات مُجمَّع لتطبيقات Flutter، أنشأه Remi Rousselet في 2021 كخلف لـ Provider. يحل Riverpod المشكلات الأساسية لـ Provider: عدم وجود التحقق في وقت التجميع، والاعتماد على BuildContext، والتعقيد مع ProviderNotFoundException. وفقًا لـ pub.dev، تجاوزت الحزمة 5 آلاف إعجاب وتحل محل Provider بنشاط في المشاريع الجديدة.

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

  • ProviderRef — كائن للوصول إلى مقدمي الخدمة الآخرين داخل المزود
  • AsyncValue — غلاف للبيانات غير المتزامنة مع حالات التحميل/الخطأ/البيانات
  • Notifier — فئة للحالة القابلة للتغيير مع طرق التعديل
  • ProviderScope — الأداة الجذرية التي تدير جميع مقدمي الخدمة
  • Code Generation — تعليقات @riverpod للتوليد التلقائي لمقدمي الخدمة

ما هو Riverpod؟

Riverpod هي مكتبة لإدارة الحالة وحقن التبعيات لتطبيقات Flutter تقوم بتجميع أوصاف مقدمي الخدمة إلى كود Dart آمن. على عكس Provider، مقدمي الخدمة في Riverpod غير مرتبطين بـ BuildContext: يتم إنشاؤهم عالميًا أو في ProviderScope ويمكن الوصول إليهم من أي مكان. يتحقق المترجم من الأنواع والتبعيات وسلامة رسم بياني لمقدمي الخدمة في وقت البناء، مما يلغي أخطاء وقت التشغيل مثل ProviderNotFoundException.

يستخدم Riverpod نموذج override للاختبار: يمكن تجاوز كل مزود عبر ProviderScope.overrideWithout الحاجة إلى إنشاء فئات فرعية أو محاكاة واجهات. هذا يجعل الاختبار معزولاً: يحصل كل اختبار على نسخته الخاصة من رسم بياني التبعيات التي يتم التحكم فيها بالكامل.

وفقًا لـ Flutter Community Survey 2025، يحتل Riverpod المركز الثالث من حيث الشعبية بعد Provider و BLoC. ومع ذلك، فإن Riverpod هو الحزمة الأسرع نموًا: +120% تثبيت في 2024. الأسباب الرئيسية: الأمان في وقت التجميع، عدم وجود ProviderNotFoundException، دعم غير متزامن مدمج عبر AsyncValue.

أنواع مقدمي الخدمة

Riverpod يوفر 8 أنواع من مقدمي الخدمة، كل منها لسيناريو محدد: Provider (ثابت/خدمة)، StateProvider (حالة بدائية)، StateNotifierProvider (منطق معقد مع StateNotifier)، ChangeNotifierProvider (للترحيل من Provider)، FutureProvider (بيانات غير متزامنة، لمرة واحدة)، StreamProvider (تدفق تفاعلي)، NotifierProvider (API جديد، Flutter 3.10+) و AsyncNotifierProvider (Notifier غير متزامن).

Dart
final counterProvider = StateNotifierProvider<CounterNotifier, int>((ref) {
  return CounterNotifier();
});

class CounterNotifier extends StateNotifier<int> {
  CounterNotifier() : super(0);

  void increment() => state++;
  void decrement() => state--;
}

class CounterScreen extends ConsumerWidget {
  @override
  Widget build(BuildContext context, WidgetRef ref) {
    final count = ref.watch(counterProvider);
    return Text('$count');
  }
}

ProviderRef — كائن يتم تمريره لكل مزود للوصول إلى مقدمي الخدمة الآخرين. ref.watch — اشتراك في التغييرات، ref.read — قراءة لمرة واحدة، ref.invalidate — إعادة تعيين الذاكرة المؤقتة. يستبدل ProviderRef BuildContext من Provider: يمكن لأي مزود قراءة مقدمي الخدمة الآخرين دون الوصول إلى شجرة الأدوات. هذا يسمح ببناء رسم بياني للتبعيات خارج طبقة واجهة المستخدم.

ProviderScope — الأداة الجذرية، إلزامية لعمل Riverpod. يخزن ProviderScope جميع مقدمي الخدمة، ويدير دورة حياتهم ويخزن القيم مؤقتًا. بدون ProviderScope سيتعطل التطبيق مع ProviderNotFoundException. يمكن أن يكون ProviderScope متداخلاً — النطاق المتداخل يتجاوز مقدمي الخدمة الأصل، مما يستخدم للاختبار وعزل الميزات.

AsyncValue والعمل مع عدم التزامن

AsyncValue — فئة مختومة من Riverpod لتمثيل الحالة غير المتزامنة. AsyncValue له ثلاثة أشكال: AsyncData (بيانات ناجحة)، AsyncError (خطأ)، AsyncLoading (تحميل). بدلاً من التبديل اليدوي بين التحميل/الخطأ/البيانات، كل FutureProvider أو StreamProvider يعيد تلقائيًا AsyncValue، وتتعامل الأداة مع جميع الحالات الثلاث عبر ref.watch.

Dart
final userProvider = FutureProvider((ref) async {
  final api = ref.watch(apiProvider);
  return await api.fetchUser();
});

class UserScreen extends ConsumerWidget {
  @override
  Widget build(BuildContext context, WidgetRef ref) {
    final userAsync = ref.watch(userProvider);
    return userAsync.when(
      data: (user) => UserWidget(user),
      error: (e, _) => ErrorWidget(e.toString()),
      loading: () => CircularProgressIndicator(),
    );
  }
}

AsyncValue.when — طريقة لمطابقة الأنماط لجميع الحالات الثلاث. يتحقق المترجم من معالجة جميع الحالات الثلاث — إذا نسيت التحميل أو الخطأ، لن يتم تجميع الكود. AsyncValue.whenData — فقط للبيانات (إذا لم يكن التحميل/الخطأ ضروريين). AsyncValue.guard — غلاف حول try-catch لتحويل الاستثناءات إلى AsyncError. keepAlive — علامة تمنع تدمير ذاكرة التخزين المؤقت للمزود عند الخروج من النطاق.

توليد الكود و @riverpod

توليد الكود — ميزة رئيسية في Riverpod 2.0+. التعليق @riverpod على دالة يولد تلقائيًا مزودًا بالنوع الصحيح ودعم إعادة الهيكلة والإكمال التلقائي. يستخدم توليد الكود riverpod_generator و build_runner. يكتب المطور دالة نقية، وكل شيء آخر — الأنواع والفئات والمنشئات المصنعية — يتم توليده تلقائيًا.

Dart
@riverpod
String helloWorld(HelloWorldRef ref) {
  return 'Hello World';
}

// تم التوليد: final helloWorldProvider = Provider((ref) => 'Hello World');

@riverpod
class Counter extends _$Counter {
  int build() => 0;
  void increment() => state++;
}

Notifier — API الجديد للحالة القابلة للتغيير مع توليد الكود. Notifier هو فئة بطريقة build() وطرق تغيير الحالة. على عكس StateNotifier، لا يتطلب Notifier فئة حالة منفصلة ويوفر وصولاً مباشرًا إلى state عبر getter/setter. يولد Riverpod تلقائيًا NotifierProvider لكل فئة Notifier موسومة بـ @riverpod.

build_runner: يتم تشغيل توليد الكود بأمر dart run build_runner build. الملفات المولدة لها اللاحقة .g.dart ويتم استيرادها في الكود المصدري. عندما تتغير التعليقات أو أنواع مقدمي الخدمة، يجب إعادة تشغيل توليد الكود. يوصي Riverpod 2.x بتوليد الكود لجميع المشاريع الجديدة — إنشاء مقدمي الخدمة يدويًا أصبح قديمًا.

Riverpod مقابل Provider

الاختلافات الرئيسية بين Riverpod و Provider: الاستقلال عن BuildContext، الأمان في وقت التجميع، دعم غير متزامن مدمج، التخزين المؤقت التلقائي، والاختبار عبر override. يتطلب Provider BuildContext للوصول إلى الحالة (context.watch, context.read)، يستخدم Riverpod WidgetRef ومقدمي الخدمة المعلنين عالميًا.

الخاصيةProviderRiverpod
الاعتماد على BuildContextنعملا
التحقق في وقت التجميعلانعم (عبر @riverpod)
ProviderNotFoundExceptionوقت التشغيلمستحيل
عدم التزامنيدويAsyncValue (مدمج)
الاختبارغلاف في ProviderProviderScope.overrideWith
التخزين المؤقتلاتلقائي + keepAlive

الترحيل من Provider: يدعم Riverpod ChangeNotifierProvider.adaptive لاستخدام ChangeNotifier الموجود دون إعادة كتابة. الترحيل التدريجي: أولاً تكتب الميزات الجديدة بـ Riverpod، ثم يتم استبدال مثيلات Provider القديمة بمقدمي خدمة Riverpod عبر محول. يمكن للحزمتين التعايش في مشروع واحد، مما يسمح بالترحيل دون تجميد التطوير.

اختبار Riverpod

اختبار Riverpod مبني على ProviderScope.overrideWith. يتم تجاوز كل مزود داخل ProviderScope اختباري دون محاكاة أو حاويات DI. ProviderContainer — بيئة معزولة للاختبارات بدون Flutter (Dart نقي)، مما يسمح باختبار مقدمي الخدمة دون عرض الأدوات.

Dart
import 'package:flutter_test/flutter_test.dart';
import 'package:riverpod/riverpod.dart';

void main() {
  test('Counter increments correctly', () {
    final container = ProviderContainer();
    container.read(counterProvider.notifier).increment();
    expect(container.read(counterProvider), 1);
  });

  testWidgets('UI updates on increment', (tester) async {
    await tester.pumpWidget(
      ProviderScope(
        overrides: [counterProvider.overrideWithValue(5)],
        child: CounterScreen(),
      ),
    );
    expect(find.text('5'), findsOneWidget);
  });
}

ProviderContainer — بدون Flutter. استخدم ProviderContainer لاختبارات الوحدة لمقدمي الخدمة دون أدوات. overrideWithValue — استبدال مزود بقيمة محددة. overrideWith — استبدال بمصنع مزود (لمحاكاة الخدمات). autodispose — في الاختبارات تحقق من تدمير المزود عند الخروج من النطاق باستخدام container.dispose().

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

كيف يختلف Riverpod عن BLoC؟

Riverpod هي مكتبة لإدارة الحالة مع مقدمي خدمة عالميين وAsyncValue وتوليد الكود. BLoC هو نمط معماري مع Event → Stream → State. Riverpod أسهل في التعلم ولديه تجربة مطور أفضل عبر تعليقات @riverpod. يوفر BLoC عزلًا صارمًا لمنطق الأعمال وتتبع الأحداث عبر BlocObserver. يعتمد الاختيار على نموذج المشروع: Riverpod أقرب إلى Provider، BLoC — إلى التدفقات التفاعلية.

ما هو autodispose في Riverpod؟

Autodispose هي آلية لتدمير المزود تلقائيًا عندما لا يكون أحد مشتركًا فيه. افتراضيًا، جميع مقدمي خدمة Riverpod يقومون بـ autodispose: عند خروج الأداة من الشجرة، يتم إزالة المزود من الذاكرة. keepAlive — علامة تعطل autodispose لمقدمي الخدمة الذين يجب أن يعيشوا دائمًا (عملاء API، المستودعات، الإعدادات). هذا يمنع تسرب الذاكرة — يتم تدمير مقدمي الخدمة غير المستخدمين تلقائيًا.

كيف يعمل ref.invalidate؟

ref.invalidate — طريقة تعيد تعيين ذاكرة التخزين المؤقت للمزود قسرًا. بعد invalidate، يتم إعادة إنشاء المزود عند القراءة التالية: يعيد FutureProvider تنفيذ الدالة غير المتزامنة، يعيد StreamProvider الاشتراك في التدفق. استخدم invalidate لإجبار تحديث البيانات (سحب للتحديث، تغيير المستخدم). ref.refresh — مزيج من invalidate + قراءة: يعيد التعيين ويقرأ على الفور القيمة الجديدة في عملية واحدة.

هل يمكن استخدام Riverpod بدون توليد الكود؟

نعم. يعمل Riverpod 1.x فقط بدون توليد الكود — يتم إنشاء مقدمي الخدمة يدويًا باستخدام Provider() وStateNotifierProvider() وFutureProvider() إلخ. يدعم Riverpod 2.x كلا النهجين. بدون توليد الكود هناك المزيد من الكود المتكرر ولكن لا تبعية على build_runner و dart run build_runner build. للمشاريع الصغيرة (حتى 30 مزودًا)، الإنشاء اليدوي مبرر؛ للمشاريع الكبيرة، توليد الكود إلزامي.

ما هي مقدمي الخدمة Family؟

Family — معدّل مزود يقبل معلمة خارجية. على سبيل المثال، userProvider(123) — مزود يقوم بتحميل مستخدم بالمعرف 123. مقدمي الخدمة Family يخزنون النتيجة مؤقتًا لكل معلمة فريدة بشكل منفصل. استخدم Family لقوائم العناصر حيث يتم تحميل كل عنصر بالمعرف. يتوفر معدّل Family لجميع أنواع مقدمي الخدمة: Provider.family وFutureProvider.family وStreamProvider.family.

الخلاصة

  • Riverpod — مدير حالة مُجمَّع، خلف لـ Provider بدون ProviderNotFoundException
  • ProviderRef — بديل لـ BuildContext للوصول إلى مقدمي الخدمة داخل مقدمي الخدمة الآخرين
  • AsyncValue — فئة مختومة بحالات التحميل/الخطأ/البيانات للبيانات غير المتزامنة
  • توليد الكود @riverpod — استنتاج تلقائي للأنواع ومصانع مقدمي الخدمة
  • ProviderScope.overrideWith — اختبار معزول بدون محاكاة وحاويات DI
  • Family — مقدمي خدمة معاملين مع تخزين مؤقت فردي
  • autodispose و keepAlive — إدارة تلقائية لدورة حياة مقدمي الخدمة

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

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

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

اقرأ أيضًا