Ответ
Да, Riverpod стал моим основным выбором для управления состоянием в новых Flutter-проектах. Я рассматриваю его как эволюцию Provider, исправляющую его ключевые боли и предлагающую более мощную, безопасную и гибкую систему.
Ключевые преимущества, которые я ценю на практике:
- Компиляционно-безопасный: Ошибки, связанные с неправильным типом провайдера или его отсутствием, отлавливаются на этапе компиляции, а не во время выполнения.
- Не зависит от BuildContext: Провайдеры можно читать и слушать в любом месте Dart-кода (в бизнес-логике, сервисах), что сильно упрощает архитектуру.
- Гибкая система провайдеров: Разные типы для разных задач (
Provider,StateProvider,StateNotifierProvider,FutureProvider,StreamProvider). - Встроенные возможности: Автоматическое кэширование, отмена запросов у
FutureProvider/StreamProvider,ref.watchдля реактивности иref.readдля разовых действий.
Пример из реального проекта:
// 1. Провайдер для сервиса (не зависит от UI)
final apiClientProvider = Provider<ApiClient>((ref) {
final dio = ref.read(dioProvider); // Читаем другой провайдер
return ApiClient(dio);
});
// 2. StateNotifierProvider для сложной бизнес-логики
final authStateProvider = StateNotifierProvider<AuthNotifier, AuthState>((ref) {
final api = ref.watch(apiClientProvider); // Реактивная зависимость
return AuthNotifier(api);
});
// 3. FutureProvider для асинхронных данных с кэшированием
final userProfileProvider = FutureProvider<UserProfile>((ref) async {
final userId = ref.watch(authStateProvider.select((s) => s.userId));
final api = ref.read(apiClientProvider);
return await api.fetchUserProfile(userId!);
});
Использование в виджете с ConsumerWidget или ConsumerStatefulWidget:
class ProfileScreen extends ConsumerWidget {
@override
Widget build(BuildContext context, WidgetRef ref) {
// ref заменяет context для доступа к провайдерам
final authState = ref.watch(authStateProvider);
final userProfileAsync = ref.watch(userProfileProvider);
return userProfileAsync.when(
data: (profile) => Scaffold(
appBar: AppBar(title: Text(profile.name)),
body: ...,
),
loading: () => Center(child: CircularProgressIndicator()),
error: (err, stack) => Center(child: Text('Error: $err')),
);
}
}
Мой опыт: Я использовал Riverpod для построения масштабируемой архитектуры в коммерческом приложении. Возможность легко комбинировать провайдеры, создавать производные состояния с select и иметь всю бизнес-логику, полностью отделённую от UI-слоя, значительно повысило тестируемость и поддерживаемость кода.