Налаштування архітектури Riverpod для Flutter-додатків
Riverpod — переосмислення Provider від того ж автора (Remi Rousselet). Він усуває головний недолік Provider: залежність від BuildContext. У Riverpod провайдери оголошуються глобально як константи, доступні з будь-якої точки коду — включаючи не-віджетний код, тести, сервіси. З виходом Riverpod 2.x та code generation через riverpod_annotation бойлерплейт скоротився до мінімуму.
Сучасний Riverpod з @riverpod
@riverpod
UserRepository userRepository(UserRepositoryRef ref) {
return UserRepositoryImpl(ref.watch(httpClientProvider));
}
@riverpod
class ProfileNotifier extends _$ProfileNotifier {
@override
FutureOr<UserProfile> build(String userId) async {
return ref.watch(userRepositoryProvider).getProfile(userId);
}
Future<void> refresh() async {
ref.invalidateSelf();
await future;
}
}
Генератор riverpod_generator створює profileNotifierProvider(userId) з цього коду. AsyncNotifier автоматично керує AsyncValue<UserProfile> — loading, data, error.
У віджеті:
class ProfileScreen extends ConsumerWidget {
final String userId;
const ProfileScreen({required this.userId});
@override
Widget build(BuildContext context, WidgetRef ref) {
final profileAsync = ref.watch(profileNotifierProvider(userId));
return profileAsync.when(
loading: () => const CircularProgressIndicator(),
error: (err, _) => ErrorView(message: err.toString()),
data: (profile) => ProfileView(profile: profile),
);
}
}
Перевага перед Provider: комбінування провайдерів
Riverpod дозволяє провайдерам залежати один від одного через ref.watch. Це працює поза деревом віджетів:
@riverpod
Future<List<Post>> filteredFeed(FilteredFeedRef ref) async {
final feed = await ref.watch(feedProvider.future);
final filters = ref.watch(contentFiltersProvider);
return feed.where((p) => filters.allows(p)).toList();
}
Якщо contentFiltersProvider змінився — filteredFeed автоматично пересчитається. У Provider це вимагає ProxyProvider з ручною інвалідацією.
Тестування
test('ProfileNotifier returns profile', () async {
final container = ProviderContainer(overrides: [
userRepositoryProvider.overrideWithValue(MockUserRepository()),
]);
final notifier = container.read(profileNotifierProvider('user-1').notifier);
expect(
await container.read(profileNotifierProvider('user-1').future),
equals(tProfile),
);
container.dispose();
});
Тест не потребує pumpWidget, Flutter SDK не потрібен. Це робить тести Riverpod найшвидшими серед усіх Flutter state management рішень.
Що налаштовуємо
ProviderScope у корені додатку. Налаштування riverpod_annotation + build_runner. Шарувата структура: repository providers → notifier providers → widget. Приклади ref.invalidate, ref.listen, ref.onDispose для управління життєвим циклом.
Терміни
Налаштування Riverpod-архітектури з нуля: 2–3 дні. Міграція з Provider на Riverpod: 1 тиждень для проекту до 20 екранів. Вартість — індивідуально.







