Sparround

Riverpod modeli: ProviderScope və Consumer-lər

Riverpod-un əsas struktur qərarı: provider-lər widget ağacında yaşamır. Rəsmi müqayisə səhifəsi onları plain Dart objects — top-level final dəyişənlər kimi təsvir edir. Ağacda yalnız bir widget qalır: tətbiqin kökündəki ProviderScope, provider-lərin state-ini saxlayan qab.

Bundan iki nəticə çıxır:

  • Oxunuş tipə görə deyil, obyektə görədir: ref.watch(counterProvider). Deməli "ağacda bu tipdən provider yoxdur" runtime xətası aradan qalxır — provider-i import etmirsinizsə, kod kompilyasiya olunmur.
  • Eyni tipdən istənilən sayda provider ola bilər: nameProvidertitleProvider hər ikisi String qaytarsa da, qarışmır.

UI tərəfində üç giriş nöqtəsi var: ConsumerWidget (build(context, ref)), ConsumerStatefulWidget + ConsumerState (orada ref sinif səviyyəsində mövcuddur) və mövcud widget-in içində kiçik bir sahə üçün Consumer widget-i.

dart
void main() {
  // ProviderScope provider-lərin state-ini saxlayan qabdır.
  runApp(const ProviderScope(child: MyApp()));
}

// Provider top-level final dəyişəndir — ağacda deyil.
final counterProvider = NotifierProvider<Counter, int>(Counter.new);

class Counter extends Notifier<int> {
  @override
  int build() => 0; // ilkin state

  void increment() => state++;
}

// 1) ConsumerWidget: build metodunda ref var.
class CounterText extends ConsumerWidget {
  const CounterText({super.key});

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

// 2) Consumer: mövcud widget-in içində yalnız kiçik sahə.
Column(
  children: [
    const ExpensiveHeader(),
    Consumer(
      builder: (context, ref, child) => Text('${ref.watch(counterProvider)}'),
    ),
  ],
);

// 3) ConsumerStatefulWidget: initState/dispose lazım olduqda.
class ChartPage extends ConsumerStatefulWidget {
  const ChartPage({super.key});
  @override
  ConsumerState<ChartPage> createState() => _ChartPageState();
}

class _ChartPageState extends ConsumerState<ChartPage> {
  @override
  void initState() {
    super.initState();
    // ConsumerState daxilində ref sinif səviyyəsindədir.
    ref.read(counterProvider.notifier).increment();
  }

  @override
  Widget build(BuildContext context) => Text('${ref.watch(counterProvider)}');
}

Kök, provider və üç oxunuş forması.

Provider (paket)Riverpod
`MultiProvider` ağacın içindəKökdə bir `ProviderScope`, provider-lər qlobal `final` dəyişən
`BuildContext.watch<T>()``WidgetRef.watch(provider)`
`BuildContext.read<T>()``WidgetRef.read(provider)`
`BuildContext.select<T, R>()``WidgetRef.watch(provider.select(...))`
`ProxyProvider`Provider daxilində `ref.watch()`
`ChangeNotifierProxyProvider``ref.listen()`

Rəsmi DO/DON'T səhifəsinin ən sərt qaydası: provider-lər yalnız top-level `final` dəyişən kimi yaradılmalıdır. Onları sinifin içində və ya dinamik şəkildə yaratmaq — sənədin ifadəsi ilə — yaddaş sızmasına və gözlənilməz davranışa aparır. Parametr lazımdırsa, family istifadə olunur; dinamik provider yaratmaq yolu deyil.

📚 Mənbələr və sənədlər