Declarative programming
Write business logic in a manner similar to Stateless widgets.
Have your
network requests to automatically recompute when necessary and make
your logic easily reusable/composable/maintainable.
Easily implement common UI patterns
Using Riverpod, common yet complex UI patterns such as "pull to refresh"/ "search as we type"/etc... are only a few lines of code away.
Tooling ready
Riverpod enhances the compiler by having common mistakes be a compilation-error. It also provides custom lint rules and refactoring options. It even has a command line for generating docs.
Features
- ✅ Declarative programming
- ✅ Native network requests support
- ✅ Automatic loading/error handling
- ✅ Compile safety
- ✅ Type-safe query parameters
- ✅ Test ready
- ✅ Work in plain Dart (servers/CLI/...)
- ✅ Easily combinable states
- ✅ Built-in support for pull-to-refresh
- ✅ Custom lint rules
- ✅ Built-in refactorings
- ✅ Hot-reload support
- ✅ Logging
- ✅ Websocket support
- ✅ Documentation generator
場所に縛られないステート宣言
main.dart
と UI 側のコードの間を行き来する必要はもうありません。
別のパッケージ内であろうと、ウィジェットのコードと同じファイル内であろうと、場所に縛られることなくステートを宣言することができます。これによりテスト容易性を損なうことはありません。
// A shared state that can be accessed by multiple widgets at the same time.
class Count extends _$Count {
int build() => 0;
void increment() => state++;
}
// Consumes the shared state and rebuild when it changes
class Title extends ConsumerWidget {
Widget build(BuildContext context, WidgetRef ref) {
final count = ref.watch(countProvider);
return Text('$count');
}
}
ステートの再評価、UI の更新を最小限に
build
メソッドの中でリストをソート / フィルタする必要はもうありません。高度なキャッシュ手法に頼る必要もありません。
Provider
と "families" を使って、本当に必要な時に限ってリストのソートや HTTP リクエストを行えます。
List<Todo> filteredTodos(FilteredTodosRef ref) {
// Providers can consumer other providers using the "ref" object.
// With ref.watch, providers will automatically update if the watched values changes.
final List<Todo> todos = ref.watch(todosProvider);
final Filter filter = ref.watch(filterProvider);
switch (filter) {
case Filter.all:
return todos;
case Filter.completed:
return todos.where((todo) => todo.completed).toList();
case Filter.uncompleted:
return todos.where((todo) => !todo.completed).toList();
}
}
Simplify day-to-day work with refactors
Riverpod offers various refactors, such as "Wrap widget in a Consumer" and many more. See the list of refactorings.
Keep your code maintainable with lint rules
New lint-rules specific to Riverpod are implemented and more are continuously added. This ensures your code stays in the best conditions. See the list of lint rules.
Bad state とは無縁
プロバイダの監視により Bad state エラーが発生することはありません。プロバイダを適切に利用することで、常に有効な値を取得できます。
これは非同期操作により値を取得する場合も同様です。Riverpod なら、loading/error のステートを簡潔に処理することができます。
Future<Configuration> configurations(ConfigurationsRef ref) async {
final uri = Uri.parse('configs.json');
final rawJson = await File.fromUri(uri).readAsString();
return Configuration.fromJson(json.decode(rawJson));
}
class Example extends ConsumerWidget {
Widget build(BuildContext context, WidgetRef ref) {
final configs = ref.watch(configurationsProvider);
// Use pattern matching to safely handle loading/error states
return switch (configs) {
AsyncData(:final value) => Text('data: ${value.host}'),
AsyncError(:final error) => Text('error: $error'),
_ => const CircularProgressIndicator(),
};
}
}
DevTools によるステートの検証
Riverpod では特別な設定をすることなく Flutter の DevTools でステートを検証することができます。
加えて、より本格的なステート検証ツールの開発が進行中です。