Riverpod 是 Provider 的升级版,解决了 Provider 的一些痛点,如编译时安全、测试友好性和更好的依赖管理。
1. 基础概念和设置
安装
# pubspec.yaml dependencies: flutter_riverpod: ^2.4.0 riverpod_annotation: ^2.3.0 dev_dependencies: build_runner: ^2.4.0 riverpod_generator: ^2.3.0
应用包装
void main() { runApp( // 用 ProviderScope 包装整个应用 ProviderScope( child: MyApp(), ), ); }
2. 主要的 Provider 类型
2.1 Provider - 最基本的 Provider
// 创建 Provider final counterProvider = Provider<int>((ref) { return 0; }); // 使用(在 ConsumerWidget 或 Consumer 中) class MyWidget extends ConsumerWidget { @override Widget build(BuildContext context, WidgetRef ref) { final counter = ref.watch(counterProvider); return Text('Count: $counter'); } }
2.2 StateProvider - 管理简单状态
final counterStateProvider = StateProvider<int>((ref) => 0); class CounterWidget extends ConsumerWidget { @override Widget build(BuildContext context, WidgetRef ref) { final counter = ref.watch(counterStateProvider); return Column( children: [ Text('Count: $counter'), ElevatedButton( onPressed: () { // 更新状态 ref.read(counterStateProvider.notifier).state++; }, child: Text('Increment'), ), ], ); } }
2.3 StateNotifierProvider - 管理复杂状态
// 定义 StateNotifier class CounterNotifier extends StateNotifier<int> { CounterNotifier() : super(0); void increment() => state++; void decrement() => state--; void reset() => state = 0; } // 创建 Provider final counterNotifierProvider = StateNotifierProvider<CounterNotifier, int>( (ref) => CounterNotifier(), ); // 使用 class CounterPage extends ConsumerWidget { @override Widget build(BuildContext context, WidgetRef ref) { final count = ref.watch(counterNotifierProvider); final counterNotifier = ref.read(counterNotifierProvider.notifier); return Scaffold( body: Center( child: Text('Count: $count'), ), floatingActionButton: FloatingActionButton( onPressed: counterNotifier.increment, child: Icon(Icons.add), ), ); } }
2.4 FutureProvider - 处理异步数据
final userDataProvider = FutureProvider<User>((ref) async { // 模拟 API 调用 final response = await http.get(Uri.parse('https://api.example.com/user')); return User.fromJson(json.decode(response.body)); }); class UserProfile extends ConsumerWidget { @override Widget build(BuildContext context, WidgetRef ref) { final userAsync = ref.watch(userDataProvider); return userAsync.when( loading: () => CircularProgressIndicator(), error: (error, stack) => Text('Error: $error'), data: (user) => Column( children: [ Text('Name: ${user.name}'), Text('Email: ${user.email}'), ], ), ); } }
2.5 StreamProvider - 处理数据流
final timerStreamProvider = StreamProvider<int>((ref) { return Stream.periodic(Duration(seconds: 1), (count) => count); }); class TimerWidget extends ConsumerWidget { @override Widget build(BuildContext context, WidgetRef ref) { final timerAsync = ref.watch(timerStreamProvider); return timerAsync.when( loading: () => Text('Starting timer...'), error: (error, stack) => Text('Error: $error'), data: (count) => Text('Elapsed: $count seconds'), ); } }
3. Provider 的依赖和组合
Provider 之间依赖
// 基础配置 final apiUrlProvider = Provider<String>((ref) => 'https://api.example.com'); // 依赖其他 Provider final userRepositoryProvider = Provider<UserRepository>((ref) { final apiUrl = ref.watch(apiUrlProvider); return UserRepository(apiUrl); }); // 更复杂的依赖 final userServiceProvider = Provider<UserService>((ref) { final repository = ref.watch(userRepositoryProvider); return UserService(repository); });
Family Provider - 带参数的 Provider
final userDetailProvider = FutureProvider.family<User, int>((ref, userId) async { final repository = ref.watch(userRepositoryProvider); return await repository.getUser(userId); }); // 使用 class UserDetailPage extends ConsumerWidget { final int userId; UserDetailPage({required this.userId}); @override Widget build(BuildContext context, WidgetRef ref) { final userAsync = ref.watch(userDetailProvider(userId)); return userAsync.when( // ... 处理不同状态 ); } }
4. 高级用法
状态监听和副作用
final authProvider = StateNotifierProvider<AuthNotifier, AuthState>((ref) { return AuthNotifier(); }); class AuthNotifier extends StateNotifier<AuthState> { AuthNotifier() : super(AuthState.initial()); Future<void> login(String email, String password) async { state = AuthState.loading(); try { final user = await authService.login(email, password); state = AuthState.authenticated(user); } catch (e) { state = AuthState.error(e.toString()); } } } // 监听状态变化 class AuthListener extends ConsumerWidget { @override Widget build(BuildContext context, WidgetRef ref) { // 监听状态但不重建 widget ref.listen<AuthState>(authProvider, (previous, next) { if (next is Authenticated) { // 导航到主页 Navigator.pushReplacementNamed(context, '/home'); } else if (next is AuthError) { // 显示错误提示 ScaffoldMessenger.of(context).showSnackBar( SnackBar(content: Text(next.message)), ); } }); return LoginForm(); } }
使用 Riverpod Generator (推荐)
// 使用注解简化代码 @riverpod class Counter extends _$Counter { @override int build() => 0; void increment() => state++; void decrement() => state--; } // 自动生成 counterProvider // 使用方式相同 class MyWidget extends ConsumerWidget { @override Widget build(BuildContext context, WidgetRef ref) { final count = ref.watch(counterProvider); final counter = ref.read(counterProvider.notifier); return ElevatedButton( onPressed: counter.increment, child: Text('Count: $count'), ); } }
5. 最佳实践
1. 合理使用 watch/read
class SmartWidget extends ConsumerWidget { @override Widget build(BuildContext context, WidgetRef ref) { // 需要重建时使用 watch final user = ref.watch(userProvider); // 不需要重建时使用 read(通常在回调中) void onButtonPressed() { final service = ref.read(userServiceProvider); service.updateUser(); } return Container(); } }
2. 选择性重建
// 使用 select 只监听需要的部分 class UserProfile extends ConsumerWidget { @override Widget build(BuildContext context, WidgetRef ref) { // 只当 userName 变化时重建 final userName = ref.watch(userProvider.select((user) => user.name)); return Text(userName); } }
3. 测试友好
void main() { test('counter increments', () { // 创建测试用的 ProviderContainer final container = ProviderContainer(); // 读取和测试 Provider expect(container.read(counterProvider), 0); container.read(counterProvider.notifier).increment(); expect(container.read(counterProvider), 1); }); }
6. 完整的示例结构
// providers/user_provider.dart final userProvider = StateNotifierProvider<UserNotifier, UserState>((ref) { return UserNotifier(ref.read(userServiceProvider)); }); // models/user_model.dart class User { final String id; final String name; final String email; User({required this.id, required this.name, required this.email}); } // states/user_state.dart sealed class UserState { const UserState(); } class UserInitial extends UserState {} class UserLoading extends UserState {} class UserLoaded extends UserState { final User user; const UserLoaded(this.user); } class UserError extends UserState { final String message; const UserError(this.message); } // notifiers/user_notifier.dart class UserNotifier extends StateNotifier<UserState> { final UserService _userService; UserNotifier(this._userService) : super(UserInitial()); Future<void> fetchUser(String userId) async { state = UserLoading(); try { final user = await _userService.getUser(userId); state = UserLoaded(user); } catch (e) { state = UserError(e.toString()); } } }
Riverpod 的核心优势在于它的类型安全、测试友好性和灵活性。通过合理使用不同类型的 Provider,可以构建出既清晰又强大的状态管理架构。