المزوّدات التي تراقب المزوّدات
جزء من قسم إدارة الحالة في رحلة Flutter على Coddy. الدرس 20 من 27.
تنشأ بعض الحالات من حالات أخرى: فإجمالي الدقائق هو مجموع التمارين. يمكنك جمعها في كل عنصر واجهة مستخدم يعرض الإجمالي، أو كتابتها مرة واحدة، كمزوّد يراقب مزوّدًا آخر:
final totalMinutesProvider = Provider((ref) {
final workouts = ref.watch(workoutsProvider);
return workouts.fold(0, (sum, w) => sum + w.minutes);
});تتلقى دالة المزوّد أيضًا ref. باستخدام ref.watch بداخلها، يتذكر Riverpod أن الإجمالي يعتمد على التمارين. أضف تمرينًا، وسيُعاد حساب الإجمالي، وستُعاد إعادة بناء كل عناصر واجهة المستخدم التي تراقب الإجمالي.
استخدم ref.watch هنا، وليس ref.read. يأخذ read القائمة مرة واحدة، عند حساب الإجمالي لأول مرة، ولا يتغير الإجمالي بعد ذلك أبدًا.
هذه هي فكرة أداة الوصول من قبل، على مستوى التطبيق كله: خزّن أقل قدر ممكن، واستنتج الباقي منه.
التحدي
متوسطيراقب الشريط العلوي totalMinutesProvider، لكن هذا المزوّد يُرجع دائمًا 0.
- اجعله يراقب
workoutsProviderويُرجع مجموع دقائق كل تمرين باستخدامminutes.
جرّب بنفسك
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
class Workout {
Workout(this.name, this.minutes);
final String name;
final int minutes;
}
class WorkoutLog extends Notifier<List<Workout>> {
@override
List<Workout> build() => [];
void add(Workout workout) {
state = [...state, workout];
}
}
final workoutsProvider = NotifierProvider<WorkoutLog, List<Workout>>(WorkoutLog.new);
final totalMinutesProvider = Provider((ref) {
return 0;
});
void main() {
runApp(const ProviderScope(child: MyApp()));
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return const MaterialApp(
debugShowCheckedModeBanner: false,
home: LogPage(),
);
}
}
class LogPage extends ConsumerWidget {
const LogPage({super.key});
@override
Widget build(BuildContext context, WidgetRef ref) {
final workouts = ref.watch(workoutsProvider);
final total = ref.watch(totalMinutesProvider);
return Scaffold(
appBar: AppBar(title: Text('Total: $total min')),
body: Column(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
ElevatedButton(
onPressed: () => ref.read(workoutsProvider.notifier).add(Workout('Run', 30)),
child: const Text('Run'),
),
const SizedBox(width: 16),
ElevatedButton(
onPressed: () => ref.read(workoutsProvider.notifier).add(Workout('Yoga', 20)),
child: const Text('Yoga'),
),
],
),
Expanded(
child: ListView(
children: [
for (final w in workouts) ListTile(title: Text(w.name), trailing: Text('${w.minutes} min')),
],
),
),
],
),
);
}
}
يتضمن هذا الدرس اختبارًا قصيرًا. ابدأ الدرس للإجابة عليه وتتبّع تقدمك.
جميع دروس إدارة الحالة
1رفع الحالة إلى المكوّن الأب
تمرير الحالة إلى مكوّن فرعيتمرير دالة رد نداء إلى مكوّن فرعيدوال رد النداء التي ترسل قيمةرفع الحالة إلى المكوّن الأب4Riverpod
Riverpod: ProviderScopeConsumerWidget و ref.watchRiverpod: StateProviderRiverpod: Notifierالمزوّدات التي تراقب المزوّداتاختيار مكان وجود الحالةتدرّب بنفسك: مترجم Flutter عبر الإنترنت