Skip to main content

Riverpod Dart

Riverpod - A Comprehensive Guide

Introduction

Riverpod is a state-management library for building Flutter applications. It is designed to make it easier to manage and share state across your application. Riverpod is built on top of the provider package and provides a more robust and intuitive API for managing your application's state.

History

Riverpod was created by Remi Rousselet and was first released in January 2021. It was born out of the need for a more powerful and flexible state management solution for Flutter applications. Since its release, Riverpod has gained popularity among Flutter developers due to its simplicity and performance.

Features

1. Dependency Injection

Riverpod provides a powerful dependency injection system that allows you to easily manage and instantiate your dependencies. It uses the concept of providers to define and expose dependencies to your application. Here's an example:

final counterProvider = Provider((ref) => Counter());

In the above code snippet, we define a counterProvider that creates an instance of the Counter class. This provider can then be used anywhere in your application to access the counter instance.

2. Scoped Providers

Riverpod also supports scoped providers, which allow you to limit the scope of a provider to a specific part of your application. This is useful when you want to share state between widgets within a specific subtree. Here's an example:

final currentThemeProvider = ScopedProvider<Theme>((ref) {
final themeId = ref.watch(themeIdProvider);
return ThemeManager.getTheme(themeId);
});

In the above code snippet, we define a currentThemeProvider that depends on the themeIdProvider and returns a specific theme based on the current theme ID.

3. State Management

Riverpod provides a simple and intuitive way to manage your application's state. It allows you to define state providers that can be mutated and accessed from anywhere in your application. Here's an example:

final counterProvider = StateProvider((ref) => 0);

// Usage
final counter = useProvider(counterProvider);
counter.state++;

In the above code snippet, we define a counterProvider that exposes a mutable state. We can then use the useProvider hook to access and mutate the counter state.

4. State Notifier

Riverpod also provides a StateNotifier class that makes it easy to manage mutable state in a more structured manner. StateNotifier is similar to StateProvider, but it encapsulates the logic for updating the state. Here's an example:

class CounterNotifier extends StateNotifier<int> {
CounterNotifier() : super(0);

void increment() {
state++;
}
}

final counterProvider = StateNotifierProvider((ref) => CounterNotifier());

// Usage
final counter = useProvider(counterProvider);
counter.increment();

In the above code snippet, we define a CounterNotifier that extends the StateNotifier class. We can then use the increment method to update the counter state.

5. Asynchronous State

Riverpod also supports managing asynchronous state using the FutureProvider and StreamProvider classes. These providers allow you to easily handle async operations and update your UI accordingly. Here's an example:

final userDataProvider = FutureProvider<User>((ref) async {
final userId = ref.watch(userIdProvider).state;
final response = await ApiService.getUser(userId);
return User.fromJson(response);
});

In the above code snippet, we define a userDataProvider that fetches user data asynchronously. The provider will automatically update the UI when the future completes.

Examples

Example 1: Counter App

Let's create a simple counter app using Riverpod. Here's the code:

final counterProvider = StateProvider((ref) => 0);

class CounterApp extends StatelessWidget {

Widget build(BuildContext context) {
final counter = useProvider(counterProvider);

return Scaffold(
appBar: AppBar(
title: Text('Counter App'),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
'Counter Value:',
style: TextStyle(fontSize: 24),
),
Text(
'${counter.state}',
style: TextStyle(fontSize: 48),
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: () => counter.state++,
child: Icon(Icons.add),
),
);
}
}

In the above code snippet, we define a counterProvider and use it inside the CounterApp widget. The counter value is displayed in the UI, and the floating action button increments the counter state when pressed.

Example 2: Scoped Providers

Let's create a themed app using scoped providers. Here's the code:

final themeIdProvider = Provider((ref) => 1);

final currentThemeProvider = ScopedProvider<Theme>((ref) {
final themeId = ref.watch(themeIdProvider);
return ThemeManager.getTheme(themeId);
});

class ThemedApp extends StatelessWidget {

Widget build(BuildContext context) {
final currentTheme = useProvider(currentThemeProvider);

return MaterialApp(
theme: currentTheme,
home: Scaffold(
appBar: AppBar(
title: Text('Themed App'),
),
body: Center(
child: Text(
'This app uses a themed UI!',
style: TextStyle(fontSize: 24),
),
),
),
);
}
}

In the above code snippet, we define a themeIdProvider and a currentThemeProvider that depends on the themeIdProvider. The ThemedApp widget uses the current theme to style its UI.

Conclusion

Riverpod is a powerful state-management library for Flutter applications. It provides a wide range of features, including dependency injection, scoped providers, and various state management techniques. With its intuitive API and excellent performance, Riverpod is a great choice for managing state in your Flutter projects.

For more information and detailed documentation, you can visit the official Riverpod website: https://riverpod.dev