كيف تدير الحالة في Flutter بسهولة؟
إدارة الحالة في Flutter
إدارة الحالة هي أحد أهم المفاهيم في تطوير تطبيقات Flutter. تتعلق بكيفية تخزين وتحديث البيانات في تطبيقك، وكيف تتفاعل واجهة المستخدم مع هذه التغييرات. في هذا الدرس، سنتعرف على مختلف طرق إدارة الحالة في Flutter، من الأساليب البسيطة إلى الحلول المتقدمة.
في هذا الدرس سنتعلم:
- مفهوم الحالة في Flutter
- إدارة الحالة المحلية باستخدام StatefulWidget
- إدارة الحالة العامة باستخدام Provider
- استخدام Riverpod للإدارة المتقدمة للحالة
- أفضل الممارسات في إدارة حالة التطبيق
مفهوم الحالة في Flutter
الحالة في Flutter هي أي بيانات قد تتغير مع مرور الوقت. على سبيل المثال:
- قيمة حقل نصي
- بيانات مستخدم مسجل الدخول
- نتائج استدعاء API
- حالة تحميل البيانات
- تحديد عنصر في قائمة
إدارة الحالة المحلية
StatefulWidget هو الأسلوب الأساسي لإدارة الحالة المحلية في Flutter. يستخدم عندما تحتاج إلى تغيير حالة widget معين:
class CounterWidget extends StatefulWidget {
@override
_CounterWidgetState createState() => _CounterWidgetState();
}
class _CounterWidgetState extends State {
int _counter = 0;
void _incrementCounter() {
setState(() {
_counter++;
});
}
@override
Widget build(BuildContext context) {
return Column(
children: [
Text('العدد الحالي: $_counter'),
ElevatedButton(
onPressed: _incrementCounter,
child: Text('زيادة'),
),
],
);
}
}
النقاط الرئيسية في المثال السابق:
setState
يخبر Flutter بأن الحالة قد تغيرت ويجب إعادة بناء الواجهة- الحالة (_counter) خاصة بهذا Widget فقط
- كل مرة يتم فيها استدعاء setState، يتم إعادة تشغيل دالة build
إدارة الحالة باستخدام Provider
Provider هو حل شائع لإدارة الحالة في Flutter عندما تحتاج إلى مشاركة البيانات بين عدة widgets. أولاً، أضف Provider إلى ملف pubspec.yaml:
dependencies:
provider: ^6.0.5
مثال على استخدام Provider:
// نموذج البيانات
class CounterModel extends ChangeNotifier {
int _count = 0;
int get count => _count;
void increment() {
_count++;
notifyListeners();
}
}
// إعداد Provider في التطبيق الرئيسي
void main() {
runApp(
ChangeNotifierProvider(
create: (context) => CounterModel(),
child: MyApp(),
),
);
}
// استخدام Provider في Widget
class CounterWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Column(
children: [
// قراءة القيمة
Consumer(
builder: (context, counter, child) {
return Text('العدد: ${counter.count}');
},
),
// تحديث القيمة
ElevatedButton(
onPressed: () {
context.read().increment();
},
child: Text('زيادة'),
),
],
);
}
}
إدارة الحالة باستخدام Riverpod
Riverpod هو تطور لمكتبة Provider، يوفر مزايا إضافية مثل التحقق من الأخطاء في وقت التجميع وإدارة أفضل للموارد. أضف Riverpod إلى ملف pubspec.yaml:
dependencies:
flutter_riverpod: ^2.4.0
riverpod_annotation: ^2.1.0
dev_dependencies:
riverpod_generator: ^2.2.0
build_runner: ^2.4.0
مثال على استخدام Riverpod:
// تعريف Provider
@riverpod
class Counter extends _$Counter {
@override
int build() => 0;
void increment() => state++;
}
// استخدام Riverpod في التطبيق
void main() {
runApp(
ProviderScope(
child: MyApp(),
),
);
}
// استخدام Provider في Widget
class CounterWidget extends ConsumerWidget {
@override
Widget build(BuildContext context, WidgetRef ref) {
final count = ref.watch(counterProvider);
return Column(
children: [
Text('العدد: $count'),
ElevatedButton(
onPressed: () => ref.read(counterProvider.notifier).increment(),
child: Text('زيادة'),
),
],
);
}
}
مثال تطبيقي: تطبيق قائمة المهام
لنقم بتطبيق ما تعلمناه في مثال عملي لتطبيق قائمة المهام باستخدام Provider:
// نموذج المهمة
class Task {
final String id;
final String title;
bool isCompleted;
Task({
required this.id,
required this.title,
this.isCompleted = false,
});
}
// نموذج إدارة المهام
class TasksModel extends ChangeNotifier {
List _tasks = [];
List get tasks => _tasks;
void addTask(String title) {
final task = Task(
id: DateTime.now().toString(),
title: title,
);
_tasks.add(task);
notifyListeners();
}
void toggleTask(String id) {
final task = _tasks.firstWhere((task) => task.id == id);
task.isCompleted = !task.isCompleted;
notifyListeners();
}
void deleteTask(String id) {
_tasks.removeWhere((task) => task.id == id);
notifyListeners();
}
}
// الواجهة الرئيسية
class TasksScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('قائمة المهام'),
),
body: Column(
children: [
AddTaskWidget(),
TasksList(),
],
),
);
}
}
// إضافة مهمة جديدة
class AddTaskWidget extends StatefulWidget {
@override
_AddTaskWidgetState createState() => _AddTaskWidgetState();
}
class _AddTaskWidgetState extends State {
final _controller = TextEditingController();
@override
Widget build(BuildContext context) {
return Padding(
padding: EdgeInsets.all(16),
child: Row(
children: [
Expanded(
child: TextField(
controller: _controller,
decoration: InputDecoration(
hintText: 'أضف مهمة جديدة',
),
),
),
IconButton(
icon: Icon(Icons.add),
onPressed: () {
if (_controller.text.isNotEmpty) {
context.read().addTask(_controller.text);
_controller.clear();
}
},
),
],
),
);
}
}
// عرض قائمة المهام
class TasksList extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Consumer(
builder: (context, tasksModel, child) {
return ListView.builder(
shrinkWrap: true,
itemCount: tasksModel.tasks.length,
itemBuilder: (context, index) {
final task = tasksModel.tasks[index];
return ListTile(
title: Text(
task.title,
style: TextStyle(
decoration: task.isCompleted
? TextDecoration.lineThrough
: null,
),
),
leading: Checkbox(
value: task.isCompleted,
onChanged: (_) {
tasksModel.toggleTask(task.id);
},
),
trailing: IconButton(
icon: Icon(Icons.delete),
onPressed: () {
tasksModel.deleteTask(task.id);
},
),
);
},
);
},
);
}
}
أفضل الممارسات
- اختيار الحل المناسب: استخدم StatefulWidget للحالة المحلية، وProvider أو Riverpod للحالة العامة
- فصل المنطق: افصل منطق إدارة الحالة عن واجهة المستخدم
- تجنب إعادة البناء غير الضرورية: استخدم Consumer بحكمة لتحديث فقط الأجزاء التي تحتاج للتحديث
- التوثيق: وثق كيفية تدفق البيانات في تطبيقك
- اختبار الحالة: اكتب اختبارات للتأكد من صحة إدارة الحالة
الخاتمة
إدارة الحالة هي مفتاح بناء تطبيقات Flutter قوية وقابلة للصيانة. في هذا الدرس، تعلمنا كيفية استخدام مختلف حلول إدارة الحالة، من StatefulWidget البسيط إلى Provider وRiverpod المتقدمين. تذكر أن اختيار الحل المناسب يعتمد على حجم تطبيقك واحتياجاته.
مشروع تطبيقي:
- قم بتطوير تطبيق قائمة التسوق باستخدام Provider
- أضف ميزات مثل إضافة وحذف وتعديل العناصر
- احفظ البيانات محلياً باستخدام shared_preferences
- أضف تصفية للعناصر (الكل، المكتملة، غير المكتملة)
اترك تعليقاً