Oxumaq: watch, read, select, Consumer
Provider-də dəyəri oxumağın dörd yolu var və aralarındaki fərq abunəlik və rebuild sahəsi ilə ölçülür.
context.watch<T>()— dəyəri qaytarır və widget-i abunə edir. Dəyişiklikdə bütün `build` metodu yenidən işləyir. Yalnızbuildiçində istifadə olunur.context.read<T>()— abunəlik yaratmır.onPressedkimi callback-lərdə metod çağırmaq üçündür.context.select<T, R>((T value) => ...)— yalnız seçilmiş hissəyə abunə edir:Rdəyişməyibsə rebuild yoxdur.Consumer<T>/Selector<T, R>— abunəliyi widget səviyyəsində məhdudlaşdırır: yalnız builder-in qaytardığı hissə yenilənir.
Provider.of<T>(context, listen: false) — read-in köhnə, uzun yazılışıdır; listen: true isə watch-a bərabərdir.
| Məqsəd | Düzgün alət | Tipik səhv |
|---|---|---|
| `build`-də dəyəri göstərmək | `context.watch<T>()` və ya `Consumer<T>` | `read` istifadə etmək → UI yenilənmir |
| Düymə basılanda metod çağırmaq | `context.read<T>().doIt()` | `watch` istifadə etmək → lazımsız abunəlik |
| Modelin yalnız bir sahəsini izləmək | `context.select((T v) => v.field)` / `Selector` | Bütün modeli `watch` etmək → hər dəyişiklikdə rebuild |
| `initState`-də ilkin dəyər almaq | `context.read<T>()` | `watch` çağırmaq → framework qadağası |
Rəsmi Flutter sənədinin birbaşa tövsiyəsi: `Consumer` widget-lərini ağacda mümkün qədər dərində yerləşdirin — kiçik bir detal dəyişdiyi üçün UI-ın böyük hissəsini yenidən qurmaq istəmirsiniz. Provider sənədi isə əksini xəbərdarlıq edir: read-i build metodunda dəyər oxumaq üçün istifadə etməyin, watch üçün isə initState yeri deyil.
// ❌ Bütün ekran səbətin hər dəyişikliyində rebuild olunur.
@override
Widget build(BuildContext context) {
final cart = context.watch<CartModel>();
return Column(
children: [
const ExpensiveBanner(),
HeavyProductGrid(items: allProducts),
Text('Cəmi: ${cart.totalPrice}'),
],
);
}
// ✅ Yalnız Text rebuild olunur; grid child kimi ötürülür.
@override
Widget build(BuildContext context) {
return Column(
children: [
const ExpensiveBanner(),
HeavyProductGrid(items: allProducts),
Consumer<CartModel>(
builder: (context, cart, child) => Text('Cəmi: ${cart.totalPrice}'),
),
],
);
}
// ✅ Yalnız bir sahəyə abunəlik: səbətə element əlavə olunsa da,
// totalPrice dəyişməyibsə rebuild olunmur.
final total = context.select<CartModel, double>((c) => c.totalPrice);`Consumer`-in `child` parametri: dəyişməyən ağır hissə bir dəfə qurulur.
📚 Mənbələr və sənədlər
- package:provider — oxunuş API-larırəsmipub.dev
watch, read, select, Consumer, Selector və DO/DON'T qeydləri README-də.
- Sadə app state: Consumer-i dərində saxlamaqrəsmidocs.flutter.dev
Consumer-in yerləşdirilməsi və child optimizasiyası haqqında rəsmi tövsiyə.
- dependOnInheritedWidgetOfExactTyperəsmiapi.flutter.dev
watch-ın altındaki çağırış: O(1)-dir, lakin initState-dən çağırılmamalıdır.