إدارة الحالة في Flutter: تطبيق الأنماط المتقدمة للمطورين
إدارة الحالة هي حجر الأساس في تطوير تطبيقات Flutter الحديثة. في هذا الدليل الشامل، سنتعمق في جميع جوانب إدارة الحالة، من المفاهيم الأساسية إلى الأنماط المتقدمة.
- فهم مفهوم الحالة وأنواعها في Flutter
- التعرف على مختلف حلول إدارة الحالة
- متى وكيف تستخدم كل حل
- أفضل الممارسات والأنماط المتقدمة
1. مفهوم الحالة في Flutter
الحالة في Flutter هي أي معلومات يمكن أن تتغير مع مرور الوقت وتؤثر على مظهر التطبيق. تنقسم الحالة إلى عدة أنواع:
- الحالة المؤقتة (Ephemeral State): حالة محلية تؤثر على widget واحد فقط
- حالة التطبيق (App State): حالة مشتركة بين عدة أجزاء من التطبيق
- الحالة المستمرة (Persistent State): بيانات تحتاج للحفظ محلياً أو على الخادم
2. إدارة الحالة المحلية باستخدام setState
setState هي الطريقة الأساسية لإدارة الحالة في Flutter. مناسبة للحالات البسيطة والمحلية.
class CounterWidget extends StatefulWidget {
@override
_CounterWidgetState createState() => _CounterWidgetState();
}
class _CounterWidgetState extends State<CounterWidget> {
int _counter = 0;
bool _isEven = true;
void _incrementCounter() {
setState(() {
_counter++;
_isEven = _counter % 2 == 0;
});
}
@override
Widget build(BuildContext context) {
return Column(
children: [
Text(
'العدد: $_counter',
style: TextStyle(
fontSize: 24,
color: _isEven ? Colors.green : Colors.red,
),
),
ElevatedButton(
onPressed: _incrementCounter,
child: Text('زيادة'),
),
],
);
}
}
- استخدم setState عندما تكون الحالة محلية لـ widget واحد
- تجنب استخدام setState للحالات المعقدة أو المشتركة
- تأكد من استدعاء setState داخل الـ State class
3. إدارة الحالة باستخدام Provider
Provider هو حل متقدم لإدارة الحالة يسمح بمشاركة البيانات بين widgets المختلفة بسهولة.
// نموذج البيانات
class CartModel extends ChangeNotifier {
final List<String> _items = [];
List<String> get items => _items;
void addItem(String item) {
_items.add(item);
notifyListeners();
}
void removeItem(String item) {
_items.remove(item);
notifyListeners();
}
}
// استخدام Provider في التطبيق
void main() {
runApp(
ChangeNotifierProvider(
create: (context) => CartModel(),
child: MyApp(),
),
);
}
// عرض البيانات
class CartView extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Consumer<CartModel>(
builder: (context, cart, child) {
return Column(
children: [
Text('عدد العناصر: ${cart.items.length}'),
ListView.builder(
itemCount: cart.items.length,
itemBuilder: (context, index) {
return ListTile(
title: Text(cart.items[index]),
trailing: IconButton(
icon: Icon(Icons.remove),
onPressed: () {
cart.removeItem(cart.items[index]);
},
),
);
},
),
],
);
},
);
}
}
4. أفضل الممارسات في إدارة الحالة
- اختيار الحل المناسب:
- setState: للحالات البسيطة والمحلية
- Provider: للتطبيقات المتوسطة وإدارة الحالة المشتركة
- BLoC: للتطبيقات الكبيرة والمعقدة
- تنظيم الكود:
- فصل منطق الأعمال عن واجهة المستخدم
- استخدام نماذج البيانات (Models)
- تجزئة الحالة إلى وحدات منطقية
- الأداء:
- تجنب إعادة البناء غير الضرورية
- استخدام Consumer بدلاً من Provider.of
- إغلاق Streams عند عدم الحاجة
5. مثال عملي: تطبيق متكامل
لنقم ببناء تطبيق متكامل يجمع بين مختلف أنماط إدارة الحالة:
// نموذج البيانات
class Product {
final String id;
final String name;
final double price;
final String imageUrl;
Product({
required this.id,
required this.name,
required this.price,
required this.imageUrl,
});
}
// حالة السلة باستخدام Provider
class CartModel extends ChangeNotifier {
final Map<String, int> _items = {};
Map<String, int> get items => _items;
int get totalItems => _items.values.fold(0, (sum, quantity) => sum + quantity);
void addItem(Product product) {
_items[product.id] = (_items[product.id] ?? 0) + 1;
notifyListeners();
}
void removeItem(String productId) {
_items.remove(productId);
notifyListeners();
}
}
// حالة المصادقة باستخدام BLoC
class AuthBloc {
final _stateController = StreamController<User?>();
Stream<User?> get user => _stateController.stream;
Future<void> login(String email, String password) async {
try {
final user = await AuthService.login(email, password);
_stateController.add(user);
} catch (e) {
_stateController.addError(e);
}
}
void logout() {
_stateController.add(null);
}
}
// الصفحة الرئيسية
class HomePage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Consumer<CartModel>(
builder: (context, cart, child) {
return Text('السلة (${cart.totalItems})');
},
),
actions: [
StreamBuilder<User?>(
stream: authBloc.user,
builder: (context, snapshot) {
if (snapshot.hasData) {
return IconButton(
icon: Icon(Icons.logout),
onPressed: () => authBloc.logout(),
);
}
return IconButton(
icon: Icon(Icons.login),
onPressed: () => Navigator.pushNamed(context, '/login'),
);
},
),
],
),
body: ProductGrid(),
);
}
}
// شبكة المنتجات
class ProductGrid extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Consumer<ProductsModel>(
builder: (context, products, child) {
return GridView.builder(
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,
childAspectRatio: 0.75,
),
itemCount: products.items.length,
itemBuilder: (context, index) {
final product = products.items[index];
return ProductCard(product: product);
},
);
},
);
}
}
// بطاقة المنتج
class ProductCard extends StatelessWidget {
final Product product;
ProductCard({required this.product});
@override
Widget build(BuildContext context) {
return Card(
child: Column(
children: [
Image.network(product.imageUrl),
Text(product.name),
Text('${product.price} د.ج'),
Consumer<CartModel>(
builder: (context, cart, child) {
return ElevatedButton(
onPressed: () => cart.addItem(product),
child: Text('إضافة للسلة'),
);
},
),
],
),
);
}
}
اترك تعليقاً