Riverpod — egy fordítási időben összeállítható állapot- és függőségkezelő Flutter-hez, amelyet Rémi Roussel hozott létre 2021-ben a Provider utódjaként. A Riverpod megoldja a Provider alapvető problémáit: a fordítási ellenőrzés hiányát, a BuildContext-től való függőséget és a ProviderNotFoundException nehézségeit. A pub.dev adatai szerint a csomag több mint 5 ezer lájkot gyűjtött, és aktívan kiszorítja a Provider-t az új projektekben.
Főbb pontok
Riverpod — egy könyvtár állapotkezeléshez és függőséginjektáláshoz Flutter-ben, amely a provider-ek leírását biztonságos Dart kódba fordítja. A Provider-rel ellentétben a Riverpod provider-ek nem kötődnek a BuildContext-hez: globálisan vagy ProviderScope-ban jönnek létre, és bárhonnan elérhetők. A fordító ellenőrzi a típusokat, függőségeket és a provider-gráf integritását az építési fázisban, kiküszöbölve a runtime hibákat, mint a ProviderNotFoundException.
A Riverpod az override modellt használja a teszteléshez: minden provider felülírható a ProviderScope.overrideWith segítségével anélkül, hogy alosztályokat kellene létrehozni vagy interfészeket mock-olni. Ez izoláltá teszi a tesztelést: minden teszt megkapja a függőségi gráf saját másolatát, amely teljes mértékben kontrollált.
A Flutter Community Survey 2025 szerint a Riverpod a harmadik helyen áll népszerűségben a Provider és a BLoC után. Ugyanakkor a Riverpod a leggyorsabban növekvő csomag: +120% telepítés 2024-ben. Fő okok: fordítási biztonság, a ProviderNotFoundException hiánya, beépített aszinkron támogatás az AsyncValue-on keresztül.
A Riverpod 8 típusú provider-t kínál, mindegyiket egy adott forgatókönyvhöz: Provider (konstans/szolgáltatás), StateProvider (primitív állapot), StateNotifierProvider (komplex logika StateNotifier-rel), ChangeNotifierProvider (Provider-ről való migráláshoz), FutureProvider (aszinkron adatok, egyszer), StreamProvider (reaktív adatfolyam), NotifierProvider (új API, Flutter 3.10+) és AsyncNotifierProvider (aszinkron 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 — az objektum, amelyet minden provider-nek átadnak más provider-ek eléréséhez. ref.watch — feliratkozás változásokra, ref.read — egyszeri olvasás, ref.invalidate — a gyorsítótár visszaállítása. A ProviderRef helyettesíti a BuildContext-et a Provider-ből: bármely provider olvashat más provider-eket anélkül, hogy hozzáférne a widget-fához. Ez lehetővé teszi a függőségi gráf felépítését az UI rétegen kívül.
ProviderScope — a Riverpod működéséhez kötelező gyökér widget. A ProviderScope tárolja az összes provider-t, kezeli azok életciklusát és gyorsítótárazza az értékeket. ProviderScope nélkül az alkalmazás ProviderNotFoundException hibával összeomlik. A ProviderScope lehet egymásba ágyazott — a beágyazott scope felülírja a szülő provider-eit, amit teszteléshez és funkciók izolálásához használnak.
AsyncValue — a Riverpod sealed osztálya az aszinkron állapot reprezentálására. Az AsyncValue-nak három változata van: AsyncData (sikeres adatok), AsyncError (hiba), AsyncLoading (betöltés). A loading/error/data közötti manuális váltogatás helyett minden FutureProvider vagy StreamProvider automatikusan AsyncValue-t ad vissza, és a widget mindhárom állapotot kezeli a ref.watch segítségével.
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 — metódus mindhárom állapot mintájának illesztésére. A fordító ellenőrzi, hogy mindhárom eset kezelve van-e — ha a loading vagy error kimarad, a kód nem fog lefordulni. AsyncValue.whenData — csak data esetén (ha loading/error nem szükséges). AsyncValue.guard — try-catch becsomagoló a kivételek AsyncError-ré alakításához. keepAlive — egy jelző, amely megakadályozza a provider gyorsítótárának megsemmisítését a láthatósági tartomány elhagyásakor.
Kódgenerálás — a Riverpod 2.0+ kulcsfontosságú jellemzője. A @riverpod annotáció egy függvény felett automatikusan létrehoz egy provider-t a megfelelő típussal, refaktorálási támogatással és automatikus kiegészítéssel. A kódgenerálás a riverpod_generator és build_runner eszközöket használja. A fejlesztő tiszta függvényt ír, és minden mást — típusokat, osztályokat, factory konstruktorokat — automatikusan generál a rendszer.
@riverpod
String helloWorld(HelloWorldRef ref) {
return 'Hello World';
}
// Generálva: final helloWorldProvider = Provider((ref) => 'Hello World');
@riverpod
class Counter extends _$Counter {
int build() => 0;
void increment() => state++;
}Notifier — új API mutable állapothoz kódgenerálással. A Notifier egy osztály build() metódussal és állapotváltoztató metódusokkal. A StateNotifier-rel ellentétben a Notifier nem igényel külön állapot osztályt, és közvetlen hozzáférést biztosít a state-hez getter/setter segítségével. A Riverpod automatikusan létrehoz NotifierProvider-t minden @riverpod annotációval rendelkező Notifier osztályhoz.
build_runner: a kódgenerálás a dart run build_runner build paranccsal indítható el. A generált fájlok .g.dart utótaggal rendelkeznek, és importálásra kerülnek a forráskódba. Az annotációk vagy provider típusok változásakor a kódgenerálást újra kell futtatni. A Riverpod 2.x a kódgenerálást ajánlja minden új projekthez — a provider-ek manuális létrehozása elavul.
Fő különbségek a Riverpod és a Provider között: függetlenség a BuildContext-től, fordítási biztonság, beépített aszinkron munka, automatikus gyorsítótárazás és tesztelés override segítségével. A Provider BuildContext-et igényel az állapot eléréséhez (context.watch, context.read), a Riverpod WidgetRef-et és globálisan deklarált provider-eket használ.
| Jellemző | Provider | Riverpod |
|---|---|---|
| Függőség BuildContext-től | Igen | Nem |
| Fordítási ellenőrzés | Nem | Igen (@riverpod segítségével) |
| ProviderNotFoundException | Runtime | Lehetetlen |
| Aszinkronitás | Manuális | AsyncValue (beépített) |
| Tesztelés | Becsomagolás Provider-be | ProviderScope.overrideWith |
| Gyorsítótárazás | Nem | Automatikus + keepAlive |
Migráció Provider-ről: A Riverpod támogatja a ChangeNotifierProvider.adaptive használatát a meglévő ChangeNotifier-ek átírás nélküli használatához. Lépésenkénti migráció: először az új funkciókat Riverpod-del írják, majd a régi Provider-eket Riverpod provider-ekre cserélik adapteren keresztül. Mindkét csomag együtt létezhet egy projektben, lehetővé téve a migrációt a fejlesztés leállítása nélkül.
A Riverpod tesztelése a ProviderScope.overrideWith-ra épül. Minden provider felülíródik a teszt ProviderScope-on belül mock-ok és DI konténerek nélkül. ProviderContainer — izolált környezet Flutter nélküli (tiszta Dart) tesztekhez, lehetővé téve a provider-ek tesztelését widget-ek megjelenítése nélkül.
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 — Flutter nélkül. Használja a ProviderContainer-t a provider-ek egységteszteléséhez widget-ek nélkül. overrideWithValue — a provider helyettesítése egy adott értékkel. overrideWith — helyettesítés provider gyárral (szolgáltatások mock-olásához). autodispose — tesztekben ellenőrizze, hogy a provider megsemmisül-e a láthatósági tartomány elhagyásakor a container.dispose() segítségével.
Gyakran Ismételt Kérdések
Riverpod — állapotkezelő könyvtár globális provider-ekkel, AsyncValue-val és kódgenerálással. BLoC — architektúra minta Event → Stream → State felépítéssel. A Riverpod könnyebben megtanulható és jobb fejlesztői élményt nyújt a @riverpod annotációkon keresztül. A BLoC szigorú üzleti logikai elkülönítést és Event-követést biztosít a BlocObserver segítségével. A választás a projekt paradigmájától függ: a Riverpod közelebb áll a Provider-hez, a BLoC a reaktív adatfolyamokhoz.
Autodispose — a provider automatikus megsemmisítésének mechanizmusa, amikor senki sincs rá feliratkozva. Alapértelmezetten minden Riverpod provider autodispose: amikor a widget elhagyja a fát, a provider törlődik a memóriából. keepAlive — egy jelző, amely kikapcsolja az autodispose-t azon provider-eknél, amelyeknek mindig élniük kell (API kliensek, repository-k, beállítások). Ez megakadályozza a memóriaszivárgást — a nem használt provider-ek automatikusan megsemmisülnek.
ref.invalidate — egy metódus, amely kényszeríti a provider gyorsítótárának visszaállítását. Az invalidate után a provider a következő olvasáskor újra létrejön: a FutureProvider újra végrehajtja az async függvényt, a StreamProvider újra feliratkozik az adatfolyamra. Használja az invalidate-t az adatok kényszerített frissítéséhez (pull-to-refresh, felhasználóváltás). ref.refresh — az invalidate + olvasás kombinációja: visszaállítja és azonnal beolvassa az új értéket egyetlen műveletben.
Igen. A Riverpod 1.x csak kódgenerálás nélkül működik — a provider-ek manuálisan jönnek létre a Provider(), StateNotifierProvider(), FutureProvider() stb. segítségével. A Riverpod 2.x mindkét megközelítést támogatja. Kódgenerálás nélkül több boilerplate van, de nincs függőség a build_runner-től és a dart run build_runner build-től. Kis projekteknél (30 provider-ig) a manuális létrehozás indokolt, nagy projekteknél a kódgenerálás kötelező.
Family — egy provider módosító, amely külső paramétert fogad el. Például userProvider(123) — egy provider, amely betölti a 123-as ID-jű felhasználót. A Family provider-ek minden egyedi paraméterhez külön gyorsítótárazzák az eredményt. Használja a Family-t olyan elemek listájához, ahol minden elem ID alapján töltődik be. A Family módosító minden provider típushoz elérhető: Provider.family, FutureProvider.family, StreamProvider.family.
Összefoglaló
Kulcsrakész mobilalkalmazást fejlesztünk
Az IT Sectr 2017 óta készít iOS és Android alkalmazásokat induló vállalkozásoknak és vállalkozásoknak. Tanácsot adunk, és a legjobb megoldást javasoljuk.
Olvassa el is