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
и {family} вы можете сортировать списки или выполнять HTTP запросы, только когда это действительно вам нужно.
List<Todo> filteredTodos(FilteredTodosRef ref) {
// Providers can consume 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.
![Simplify day-to-day work with refactors](img/intro/convert_to_class_provider.gif)
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.
![Keep your code maintainable with lint rules](img/intro/lint.gif)
Безопасное чтение провайдеров
Чтение провайдера никогда не приведет к bad state. При правильном использовании провайдера вы всегда сможете получить допустимое значение.
Это также относится к асинхронно полученным значениям. Riverpod в отличие от provider позволяет элегантно обрабатывать загрузку/ошибки.
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(),
};
}
}
Проверка вашего состояния в devtool
Riverpod делает видимым ваше состояние в Flutter devtool.
Более того, уже разрабатывается полномасштабный инспектор состояния.
![Проверка вашего состояния в devtool](img/intro/devtool.png)