Riverpod — esensya, kompilasyon ng mga dependency sa Flutter

May-akda: IT Sectr Nai-publish: 2026-02-19 Oras ng pagbabasa: 7 min

Riverpod — isang compileable state at dependency manager para sa Flutter, na nilikha ni Rémi Roussel noong 2021 bilang kahalili ng Provider. Nilulutas ng Riverpod ang mga pangunahing problema ng Provider: kawalan ng pagsusuri sa kompilasyon, pag-asa sa BuildContext at kahirapan sa ProviderNotFoundException. Ayon sa datos ng pub.dev, ang package ay nakaipon ng mahigit 5 libong likes at aktibong pinapalitan ang Provider sa mga bagong proyekto.

Mga Pangunahing Punto

  • ProviderRef — bagay para sa pag-access sa iba pang provider sa loob ng isang provider
  • AsyncValue — wrapper para sa asynchronous na datos na may mga estadong loading/error/data
  • Notifier — klase para sa mutable na estado na may mga pamamaraan ng pagbabago
  • ProviderScope — root widget na namamahala sa lahat ng provider
  • Code Generation — mga anotasyong @riverpod para sa awtomatikong pagbuo ng provider

Ano ang Riverpod?

Riverpod — isang library para sa pamamahala ng estado at dependency injection sa Flutter na nagko-compile ng paglalarawan ng provider sa ligtas na Dart code. Hindi tulad ng Provider, ang mga provider ng Riverpod ay hindi nakatali sa BuildContext: sila ay nilikha nang global o sa ProviderScope at naa-access mula sa kahit saan. Sinusuri ng compiler ang mga uri, dependency, at integridad ng graph ng provider sa yugto ng build, inaalis ang mga error sa runtime tulad ng ProviderNotFoundException.

Gumagamit ang Riverpod ng modelong override para sa pagsubok: bawat provider ay maaaring i-override sa pamamagitan ng ProviderScope.overrideWith nang hindi kinakailangang lumikha ng mga subclass o mag-mock ng mga interface. Ginagawa nitong isolated ang pagsubok: bawat pagsubok ay nakakakuha ng sarili nitong kopya ng dependency graph na ganap na kontrolado.

Ayon sa Flutter Community Survey 2025, ang Riverpod ay nasa ikatlong puwesto sa kasikatan pagkatapos ng Provider at BLoC. Kasabay nito, ang Riverpod ang pinakamabilis na lumalagong package: +120% na pag-install noong 2024. Mga pangunahing dahilan: kaligtasan sa kompilasyon, kawalan ng ProviderNotFoundException, built-in na suporta sa asynchrony sa pamamagitan ng AsyncValue.

Mga Uri ng Provider

Riverpod ay nagbibigay ng 8 uri ng provider, bawat isa para sa partikular na sitwasyon: Provider (constant/serbisyo), StateProvider (primitive na estado), StateNotifierProvider (komplikadong lohika na may StateNotifier), ChangeNotifierProvider (para sa migrasyon mula sa Provider), FutureProvider (asynchronous na datos, isang beses), StreamProvider (reactive stream), NotifierProvider (bagong API, Flutter 3.10+) at AsyncNotifierProvider (asynchronous na Notifier).

Dart
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 — ang bagay na ipinapasa sa bawat provider para sa pag-access sa iba pang provider. ref.watch — subscription sa mga pagbabago, ref.read — isang beses na pagbasa, ref.invalidate — pag-reset ng cache. Pinapalitan ng ProviderRef ang BuildContext mula sa Provider: kahit anong provider ay maaaring magbasa ng iba pang provider nang walang access sa widget tree. Ito ay nagpapahintulot sa pagbuo ng dependency graph sa labas ng UI layer.

ProviderScope — ang mandatoryong root widget para sa pagpapatakbo ng Riverpod. Iniimbak ng ProviderScope ang lahat ng provider, pinamamahalaan ang kanilang lifecycle at nag-ca-cache ng mga halaga. Kung walang ProviderScope, ang application ay babagsak na may ProviderNotFoundException. Ang ProviderScope ay maaaring nested — ang nested scope ay nag-o-override sa mga provider ng parent, na ginagamit para sa pagsubok at paghihiwalay ng feature.

AsyncValue at pagtatrabaho sa asynchrony

AsyncValue — isang sealed class ng Riverpod para sa pagrepresenta ng asynchronous na estado. Ang AsyncValue ay may tatlong variant: AsyncData (matagumpay na datos), AsyncError (error), AsyncLoading (naglo-load). Sa halip na manu-manong paglipat sa pagitan ng loading/error/data, bawat FutureProvider o StreamProvider ay awtomatikong nagbabalik ng AsyncValue, at pinangangasiwaan ng widget ang lahat ng tatlong estado sa pamamagitan ng ref.watch.

Dart
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 — pamamaraan para sa pattern matching ng lahat ng tatlong estado. Sinusuri ng compiler na ang lahat ng tatlong kaso ay napangasiwaan — kung nakalimutan ang loading o error, ang code ay hindi magko-compile. AsyncValue.whenData — para lamang sa data (kung hindi kailangan ang loading/error). AsyncValue.guard — isang try-catch wrapper para sa pag-convert ng exception sa AsyncError. keepAlive — isang bandila na pumipigil sa pagkasira ng cache ng provider kapag lumalabas sa saklaw ng visibility.

Code Generation at @riverpod

Pagbuo ng code — isang pangunahing tampok ng Riverpod 2.0+. Ang anotasyong @riverpod sa itaas ng isang function ay awtomatikong bumubuo ng provider na may tamang uri, suporta sa refactoring at autocomplete. Ang pagbuo ng code ay gumagamit ng riverpod_generator at build_runner. Ang developer ay nagsusulat ng purong function, at ang lahat ng iba pa — mga uri, klase, factory constructor — ay awtomatikong nabubuo.

Dart
@riverpod
String helloWorld(HelloWorldRef ref) {
  return 'Hello World';
}

// Nabuo: final helloWorldProvider = Provider((ref) => 'Hello World');

@riverpod
class Counter extends _$Counter {
  int build() => 0;
  void increment() => state++;
}

Notifier — isang bagong API para sa mutable na estado na may pagbuo ng code. Ang Notifier ay isang klase na may build() method at mga pamamaraan para sa pagbabago ng estado. Hindi tulad ng StateNotifier, ang Notifier ay hindi nangangailangan ng hiwalay na state class at nagbibigay ng direktang access sa state sa pamamagitan ng getter/setter. Awtomatikong bumubuo ang Riverpod ng NotifierProvider para sa bawat Notifier class na may anotasyong @riverpod.

build_runner: ang pagbuo ng code ay pinapatakbo gamit ang command na dart run build_runner build. Ang mga nabuong file ay may suffix na .g.dart at ini-import sa source code. Kapag nagbabago ang mga anotasyon o uri ng provider, kailangang i-restart ang pagbuo ng code. Inirerekomenda ng Riverpod 2.x ang pagbuo ng code para sa lahat ng bagong proyekto — ang manu-manong paglikha ng provider ay nagiging luma na.

Riverpod vs Provider

Mga pangunahing pagkakaiba ng Riverpod mula sa Provider: kalayaan mula sa BuildContext, kaligtasan sa kompilasyon, built-in na pagtatrabaho sa asynchrony, awtomatikong caching at pagsubok sa pamamagitan ng override. Ang Provider ay nangangailangan ng BuildContext para sa pag-access sa estado (context.watch, context.read), ang Riverpod ay gumagamit ng WidgetRef at globally declared provider.

KatangianProviderRiverpod
Pag-asa sa BuildContextOoHindi
Pagsusuri sa kompilasyonHindiOo (sa pamamagitan ng @riverpod)
ProviderNotFoundExceptionRuntimeImposible
AsynchronyManualAsyncValue (built-in)
PagsubokWrapper sa ProviderProviderScope.overrideWith
CachingHindiAwtomatik + keepAlive

Migrasyon mula sa Provider: Sinusuportahan ng Riverpod ang ChangeNotifierProvider.adaptive para sa paggamit ng mga umiiral na ChangeNotifier nang hindi muling nagsusulat. Step-by-step na migrasyon: una ang mga bagong feature ay isinusulat sa Riverpod, pagkatapos ang mga lumang Provider ay pinapalitan ng Riverpod provider sa pamamagitan ng adapter. Ang parehong package ay maaaring magkasama sa isang proyekto, na nagpapahintulot sa migrasyon nang hindi nagyeyelo sa pag-develop.

Pagsubok sa Riverpod

Pagsubok sa Riverpod ay batay sa ProviderScope.overrideWith. Bawat provider ay nio-override sa loob ng testing ProviderScope nang walang mock at DI container. ProviderContainer — isang isolated na kapaligiran para sa pagsubok nang walang Flutter (purong Dart), na nagpapahintulot sa pagsubok ng provider nang hindi nagre-render ng widget.

Dart
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 — walang Flutter. Gamitin ang ProviderContainer para sa unit test ng provider nang walang widget. overrideWithValue — pagpapalit ng provider ng isang tiyak na halaga. overrideWith — pagpapalit ng factory ng provider (para sa pag-mock ng serbisyo). autodispose — sa pagsubok, suriin kung ang provider ay nawasak kapag lumalabas sa saklaw ng visibility, gamit ang container.dispose().

Mga Madalas Itanong

Paano naiiba ang Riverpod sa BLoC?

Riverpod — library ng pamamahala ng estado na may global provider, AsyncValue at pagbuo ng code. BLoC — pattern ng arkitektura na may Event → Stream → State. Ang Riverpod ay mas madaling matutunan at may mas mahusay na DX sa pamamagitan ng @riverpod anotasyon. Ang BLoC ay nagbibigay ng mahigpit na paghihiwalay ng lohika ng negosyo at pagsubaybay ng Event sa pamamagitan ng BlocObserver. Ang pagpili ay depende sa paradigma ng proyekto: ang Riverpod ay mas malapit sa Provider, ang BLoC — sa reactive stream.

Ano ang autodispose sa Riverpod?

Autodispose — mekanismo ng awtomatikong pagkasira ng provider kapag walang naka-subscribe dito. Bilang default, lahat ng Riverpod provider ay autodispose: kapag lumabas ang widget sa tree, ang provider ay tinatanggal mula sa memorya. keepAlive — isang bandila na nagdi-disable ng autodispose para sa provider na dapat laging mabuhay (mga API client, repository, setting). Ito ay pumipigil sa pagtagas ng memorya — ang mga hindi ginagamit na provider ay awtomatikong nasisira.

Paano gumagana ang ref.invalidate?

ref.invalidate — isang pamamaraan na pumipilit sa pag-reset ng cache ng provider. Pagkatapos ng invalidate, ang provider ay muling lilikhain sa susunod na pagbasa: muling isasagawa ng FutureProvider ang async function, muling magse-subscribe ang StreamProvider sa stream. Gamitin ang invalidate para sa sapilitang pag-refresh ng datos (pull-to-refresh, pagpapalit ng user). ref.refresh — kombinasyon ng invalidate + pagbasa: nire-reset at agad na binabasa ang bagong halaga sa isang operasyon.

Maaari bang gamitin ang Riverpod nang walang pagbuo ng code?

Oo. Ang Riverpod 1.x ay gumagana lamang nang walang pagbuo ng code — ang provider ay nilikha nang manu-mano sa pamamagitan ng Provider(), StateNotifierProvider(), FutureProvider() atbp. Ang Riverpod 2.x ay sumusuporta sa parehong approach. Nang walang pagbuo ng code, mas maraming boilerplate, ngunit walang pag-asa sa build_runner at dart run build_runner build. Para sa maliliit na proyekto (hanggang 30 provider), ang manu-manong paglikha ay makatwiran, para sa malalaking proyekto, ang pagbuo ng code ay sapilitan.

Ano ang Family provider?

Family — isang modifier ng provider na tumatanggap ng panlabas na parameter. Halimbawa, userProvider(123) — isang provider na naglo-load ng user na may ID 123. Ang Family provider ay nag-ca-cache ng resulta para sa bawat natatanging parameter nang hiwalay. Gamitin ang Family para sa listahan ng mga elemento kung saan ang bawat elemento ay nilo-load ayon sa ID. Ang Family modifier ay available para sa lahat ng uri ng provider: Provider.family, FutureProvider.family, StreamProvider.family.

Buod

  • Riverpod — compileable state manager, kahalili ng Provider nang walang ProviderNotFoundException
  • ProviderRef — kapalit ng BuildContext para sa pag-access sa provider sa loob ng iba pang provider
  • AsyncValue — sealed class na may loading/error/data na estado para sa asynchronous na datos
  • Pagbuo ng code @riverpod — awtomatikong inference ng uri at factory ng provider
  • ProviderScope.overrideWith — isolated na pagsubok nang walang mock at DI container
  • Family — parameterized provider na may indibidwal na caching
  • autodispose at keepAlive — awtomatikong pamamahala ng lifecycle ng provider

Gagawa kami ng mobile application na turnkey

Gumagawa ang IT Sectr ng mga iOS at Android application para sa mga startup at negosyo mula noong 2017. Magpapayo kami sa iyo at magmumungkahi ng pinakamahusay na solusyon.

Pag-usapan ang proyekto

Basahin din