Riverpod — kompilovatelný správce stavu a závislostí pro Flutter, vytvořený Rémi Rousselem v roce 2021 jako nástupce Provider. Riverpod řeší zásadní problémy Provider: chybějící kontrolu při kompilaci, závislost na BuildContext a obtíže s ProviderNotFoundException. Podle údajů pub.dev balíček nasbíral přes 5 tisíc lajků a aktivně vytlačuje Provider v nových projektech.
Hlavní body
Riverpod — knihovna pro správu stavu a vkládání závislostí ve Flutter, která kompiluje popis providerů do bezpečného Dart kódu. Na rozdíl od Provider nejsou providery Riverpod vázány na BuildContext: jsou vytvářeny globálně nebo v ProviderScope a jsou přístupné odkudkoli. Kompilátor kontroluje typy, závislosti a integritu grafu providerů ve fázi sestavení, čímž eliminuje runtime chyby jako ProviderNotFoundException.
Riverpod používá model override pro testování: každý provider může být přepsán pomocí ProviderScope.overrideWith bez nutnosti vytvářet podtřídy nebo mockovat rozhraní. To činí testování izolovaným: každý test dostane svou vlastní kopii grafu závislostí, která je plně kontrolována.
Podle Flutter Community Survey 2025 je Riverpod na třetím místě v popularitě po Provider a BLoC. Riverpod je zároveň nejrychleji rostoucím balíčkem: +120% instalací v roce 2024. Hlavní důvody: bezpečnost při kompilaci, absence ProviderNotFoundException, vestavěná podpora asynchronnosti přes AsyncValue.
Riverpod poskytuje 8 typů providerů, každý pro konkrétní scénář: Provider (konstanta/služba), StateProvider (primitivní stav), StateNotifierProvider (složitá logika s StateNotifier), ChangeNotifierProvider (pro migraci z Provider), FutureProvider (asynchronní data, jednou), StreamProvider (reaktivní tok), NotifierProvider (nové API, Flutter 3.10+) a AsyncNotifierProvider (asynchronní Notifier).
final counterProvider = StateNotifierProvider<CounterNotifier, int>((ref) {
return CounterNotifier();
});
class CounterNotifier extends StateNotifier<int> {
CounterNotifier() : super(0);
void increment() => state++;
void decrement() => state--;
}
class CounterScreen extends ConsumerWidget {
@override
Widget build(BuildContext context, WidgetRef ref) {
final count = ref.watch(counterProvider);
return Text('$count');
}
}ProviderRef — objekt předávaný každému provideru pro přístup k dalším providerům. ref.watch — přihlášení ke změnám, ref.read — jednorázové přečtení, ref.invalidate — resetování cache. ProviderRef nahrazuje BuildContext z Provider: jakýkoli provider může číst jiné providery bez přístupu ke stromu widgetů. To umožňuje vytvářet graf závislostí mimo vrstvu UI.
ProviderScope — povinný kořenový widget pro fungování Riverpod. ProviderScope ukládá všechny providery, spravuje jejich životní cyklus a ukládá hodnoty do cache. Bez ProviderScope aplikace spadne s ProviderNotFoundException. ProviderScope může být vnořený — vnořený scope přepisuje providery rodiče, což se používá pro testování a izolaci funkcí.
AsyncValue — sealed třída Riverpod pro reprezentaci asynchronního stavu. AsyncValue má tři varianty: AsyncData (úspěšná data), AsyncError (chyba), AsyncLoading (načítání). Místo ručního přepínání mezi loading/error/data každý FutureProvider nebo StreamProvider automaticky vrací AsyncValue a widget zpracovává všechny tři stavy přes ref.watch.
final userProvider = FutureProvider((ref) async {
final api = ref.watch(apiProvider);
return await api.fetchUser();
});
class UserScreen extends ConsumerWidget {
@override
Widget build(BuildContext context, WidgetRef ref) {
final userAsync = ref.watch(userProvider);
return userAsync.when(
data: (user) => UserWidget(user),
error: (e, _) => ErrorWidget(e.toString()),
loading: () => CircularProgressIndicator(),
);
}
}AsyncValue.when — metoda pro pattern matching všech tří stavů. Kompilátor kontroluje, že všechny tři případy jsou zpracovány — pokud se zapomene na loading nebo error, kód se nezkompiluje. AsyncValue.whenData — pouze pro data (pokud loading/error nejsou potřeba). AsyncValue.guard — try-catch obal pro převod výjimky na AsyncError. keepAlive — příznak, který zabraňuje zničení cache provideru při opuštění rozsahu viditelnosti.
Generování kódu — klíčová vlastnost Riverpod 2.0+. Anotace @riverpod nad funkcí automaticky generuje provider se správným typem, podporou refaktorování a automatickým doplňováním. Generování kódu používá riverpod_generator a build_runner. Vývojář napíše čistou funkci a vše ostatní — typy, třídy, factory konstruktory — se generuje automaticky.
@riverpod
String helloWorld(HelloWorldRef ref) {
return 'Hello World';
}
// Vygenerováno: final helloWorldProvider = Provider((ref) => 'Hello World');
@riverpod
class Counter extends _$Counter {
int build() => 0;
void increment() => state++;
}Notifier — nové API pro měnitelný stav s generováním kódu. Notifier je třída s metodou build() a metodami pro změnu stavu. Na rozdíl od StateNotifier, Notifier nevyžaduje samostatnou třídu stavu a poskytuje přímý přístup k state přes getter/setter. Riverpod automaticky generuje NotifierProvider pro každou třídu Notifier s anotací @riverpod.
build_runner: generování kódu se spouští příkazem dart run build_runner build. Generované soubory mají příponu .g.dart a importují se do zdrojového kódu. Při změně anotací nebo typů providerů je třeba generování kódu restartovat. Riverpod 2.x doporučuje generování kódu pro všechny nové projekty — ruční vytváření providerů zastarává.
Hlavní rozdíly Riverpod oproti Provider: nezávislost na BuildContext, bezpečnost při kompilaci, vestavěná práce s asynchronností, automatické cache a testování přes override. Provider vyžaduje BuildContext pro přístup ke stavu (context.watch, context.read), Riverpod používá WidgetRef a globálně deklarované providery.
| Vlastnost | Provider | Riverpod |
|---|---|---|
| Závislost na BuildContext | Ano | Ne |
| Kontrola při kompilaci | Ne | Ano (přes @riverpod) |
| ProviderNotFoundException | Runtime | Nemožný |
| Asynchronnost | Ruční | AsyncValue (vestavěný) |
| Testování | Obal v Provider | ProviderScope.overrideWith |
| Cache | Ne | Automatické + keepAlive |
Migrace z Provider: Riverpod podporuje ChangeNotifierProvider.adaptive pro použití stávajících ChangeNotifier bez přepisování. Postupná migrace: nejprve se nové funkce píší v Riverpod, poté se staré Provider nahrazují providery Riverpod přes adaptér. Oba balíčky mohou koexistovat v jednom projektu, což umožňuje migraci bez zmrazení vývoje.
Testování Riverpod je postaveno na ProviderScope.overrideWith. Každý provider je přepsán uvnitř testovacího ProviderScope bez mocků a DI kontejnerů. ProviderContainer — izolované prostředí pro testy bez Flutter (čistý Dart), umožňující testování providerů bez vykreslování widgetů.
import 'package:flutter_test/flutter_test.dart';
import 'package:riverpod/riverpod.dart';
void main() {
test('Counter increments correctly', () {
final container = ProviderContainer();
container.read(counterProvider.notifier).increment();
expect(container.read(counterProvider), 1);
});
testWidgets('UI updates on increment', (tester) async {
await tester.pumpWidget(
ProviderScope(
overrides: [counterProvider.overrideWithValue(5)],
child: CounterScreen(),
),
);
expect(find.text('5'), findsOneWidget);
});
}ProviderContainer — bez Flutter. Použijte ProviderContainer pro unit testy providerů bez widgetů. overrideWithValue — nahrazení provideru konkrétní hodnotou. overrideWith — nahrazení továrnou provideru (pro mockování služeb). autodispose — v testech zkontrolujte, zda je provider zničen při opuštění rozsahu viditelnosti pomocí container.dispose().
Často kladené otázky
Riverpod — knihovna pro správu stavu s globálními providery, AsyncValue a generováním kódu. BLoC — architektonický vzor s Event → Stream → State. Riverpod se snadněji učí a má lepší DX díky @riverpod anotacím. BLoC poskytuje přísnou izolaci business logiky a sledování Event přes BlocObserver. Volba závisí na paradigmatu projektu: Riverpod je blíže Provider, BLoC — reaktivním tokům.
Autodispose — mechanismus automatického zničení provideru, když na něj nikdo není přihlášen. Ve výchozím nastavení jsou všechny Riverpod providery autodispose: při opuštění widgetu ze stromu je provider odstraněn z paměti. keepAlive — příznak, který vypíná autodispose pro providery, které mají žít vždy (API klienti, repozitáře, nastavení). To zabraňuje únikům paměti — nepoužívané providery jsou automaticky ničeny.
ref.invalidate — metoda, která vynuceně resetuje cache provideru. Po invalidate je provider znovu vytvořen při příštím čtení: FutureProvider znovu provede async funkci, StreamProvider se znovu přihlásí k toku. Použijte invalidate pro vynucené obnovení dat (pull-to-refresh, změna uživatele). ref.refresh — kombinace invalidate + čtení: resetuje a okamžitě přečte novou hodnotu v jedné operaci.
Ano. Riverpod 1.x funguje pouze bez generování kódu — providery se vytvářejí ručně přes Provider(), StateNotifierProvider(), FutureProvider() atd. Riverpod 2.x podporuje oba přístupy. Bez generování kódu je více boilerplate, ale není závislost na build_runner a dart run build_runner build. Pro malé projekty (do 30 providerů) je ruční vytváření ospravedlnitelné, pro velké projekty je generování kódu povinné.
Family — modifikátor provideru, který přijímá externí parametr. Například userProvider(123) — provider načítající uživatele s ID 123. Family providery ukládají výsledek pro každý jedinečný parametr zvlášť. Použijte Family pro seznam prvků, kde se každý prvek načítá podle ID. Modifikátor Family je k dispozici pro všechny typy providerů: Provider.family, FutureProvider.family, StreamProvider.family.
Shrnutí
Vyvineme mobilní aplikaci na klíč
IT Sectr vytváří aplikace pro iOS a Android pro startupy a podniky od roku 2017. Poradíme vám a navrhneme nejlepší řešení.