What is Riverpod?
Riverpod is a reactive state management library for Flutter that is built on top of the Provider package but offers several improvements. It is compile‑safe, scalable, and works seamlessly with Flutter’s reactive paradigm. Riverpod provides a way to define providers that encapsulate state and logic, and then allows widgets to read or listen to that state efficiently. It eliminates the need for BuildContext in many cases and prevents common pitfalls like accessing a provider before it exists.
Why Riverpod?
- Compile‑safe: No runtime errors for missing providers.
- Unified API: One consistent way to handle all types of state (simple values, futures, streams, mutable state).
- Scoped providers: Providers can be overridden for specific parts of the widget tree.
- Auto‑dispose: Providers can clean up resources automatically when no longer used.
- Testable: Providers can be easily mocked and overridden in tests.
Adding Riverpod to Your Project
Add the riverpod package to your pubspec.yaml:
dependencies:
flutter_riverpod: ^2.4.0
riverpod: ^2.4.0
Then run flutter pub get.
For code generation, you may also need riverpod_annotation and build_runner, but we’ll start with the simple API.
Core Concepts
Riverpod revolves around providers. A provider is a declaration of a piece of state or a service. Providers are global, but they can be overridden locally. Widgets interact with providers using ref objects obtained from ConsumerWidget or Consumer widgets.
Creating a Simple Provider
The simplest provider is Provider, which just returns a value. Use it for services or immutable data.
StateProvider for Mutable State
StateProvider holds a mutable piece of state that can be read and written.
FutureProvider for Asynchronous Data
FutureProvider handles asynchronous operations and manages loading, data, and error states.
In your widget, you can watch the provider and react to its state:
StateNotifierProvider for Complex State
For more complex state that requires methods to modify it, use StateNotifierProvider with a StateNotifier subclass. This is similar to ChangeNotifier but with better integration with Riverpod.
Reading Providers in Widgets
To access providers, you need a ref object. This is available in:
ConsumerWidget(a StatelessWidget that has arefparameter in itsbuildmethod)ConsumerStatefulWidget(StatefulWidget withrefin the State)Consumer(a widget that exposesrefto its builder)
ref.watch vs ref.read vs ref.listen
ref.watch: Listens to a provider and rebuilds the widget when the provider’s value changes. Use it to display state.
ref.read: Reads the provider’s value once without listening. Use it for actions (like button taps).
ref.listen: Listens to changes without rebuilding the widget; useful for side effects like showing a snackbar.
Provider Modifiers
Riverpod provides modifiers to adjust provider behavior:
.family: Allows you to pass parameters to a provider..autoDispose: Automatically disposes the provider when it is no longer used (e.g., when the widget that watches it is removed).
Scoping Providers
You can override a provider for a part of the widget tree using ProviderScope. This is useful for testing or providing different values in different parts of the app.
Best Practices
- Use
ref.watchonly where needed – avoid watching providers high in the tree to prevent large rebuilds.
- Use
- Prefer
ConsumerWidgetoverConsumerfor simpler code.
- Prefer
- Use
.autoDisposefor providers that are not used throughout the app’s lifetime.
- Use
- Name providers clearly (e.g.,
counterProvider,todoListNotifier).
- Name providers clearly (e.g.,
- Separate providers into logical files to keep your codebase organized.
Common Mistakes
- Calling
ref.watchinside a callback – This can cause the widget to rebuild at unexpected times. Useref.readinstead.
- Calling
- Not disposing resources – Use
autoDisposeor overridedisposein your notifier to clean up streams, controllers, etc.
- Not disposing resources – Use
- Using
ref.readto watch a provider –ref.readdoes not rebuild the widget; useref.watchfor listening.
- Using
- Passing providers as parameters – Instead, use
ref.watchinside the widget to get the value.
- Passing providers as parameters – Instead, use
Key Takeaways
- Riverpod is a modern, compile‑safe state management solution.
- Providers are the building blocks; they can be simple values, futures, streams, or mutable state.
- Use
ConsumerWidgetto get arefin your widgets.
- Use
ref.watchrebuilds the widget;ref.readgets a value without listening;ref.listenreacts to changes.
- Use
.familyto pass parameters, and.autoDisposeto clean up resources.
- Use
- Scope providers with
ProviderScopeto override values in subtrees.
- Scope providers with