原文
https://itnext.io/flutter-sta...
代码
https://github.com/iisprey/ri...
参考
- https://itnext.io/a-minimalis...
- https://pub.dev/packages/stat...
- https://iisprey.medium.com/ge...
- https://iisprey.medium.com/ho...
注释
正如我上周所承诺的,我将向您展现我本人的最终国家治理解决方案门路
Riverpod + StateNotifier + Hooks + Freezed
Riverpod 太棒了!然而好的例子并不多。只有最根本的,就这样。这一次,我试图使一个例子既可了解又简单。我的目标是通过这个例子教你什么时候应用 Riverpod,以及如何应用它。只管我简化了过程。心愿你喜爱!
动机
在这个例子中咱们要做什么?
咱们只须要从 API 中获取一些数据,而后在 UI 中对它们进行排序和过滤
基本上,咱们会;
- Create simple and complex providers and combine them
- 创立简略和简单的提供程序并将它们组合起来
- Use AsyncValue object and show async value in the UI using
when
method - 应用 AsyncValue 对象并在 UI 中应用 when 办法显示 async 值
- Also, create
freezed
objects for immutable object solution - 同时,为不可变物件/解决方案创立解冻对象
咱们开始吧!
创立 API 服务
留神: 我没有找到一个好的 API 模型来应用过滤性能,因为我本人增加了这些角色。原谅我这么说
final userService = Provider((ref) => UserService());class UserService { final _dio = Dio(BaseOptions(baseUrl: 'https://reqres.in/api/')); Future<List<User>> getUsers() async { final res = await _dio.get('users'); final List list = res.data['data']; // API didn't have user roles I just added by hand (it looks ugly but never mind) list[0]['role'] = 'normal'; list[1]['role'] = 'normal'; list[2]['role'] = 'normal'; list[3]['role'] = 'admin'; list[4]['role'] = 'admin'; list[5]['role'] = 'normal'; return list.map((e) => User.fromJson(e)).toList(); }}
应用 freezed
和 json_serializable
创立不可变模型
咱们只须要创立一个
part 'user.freezed.dart';part 'user.g.dart';@freezedclass User with _$User { @JsonSerializable(fieldRename: FieldRename.snake) const factory User({ required int id, required String email, required String firstName, required String lastName, required String avatar, @JsonKey(unknownEnumValue: Role.normal) required Role role, }) = _User; factory User.fromJson(Map<String, dynamic> json) => _$UserFromJson(json);}
如果你想理解更多对于 freezed 的信息,请查看这篇文章。
https://iisprey.medium.com/ho...
从服务中取得 value
你能够想想,AsyncValue
是什么? 它只是一个联结类,帮忙咱们解决咱们的值的状态。它提供了一个现成的提供者包。
我将在接下来的文章中具体解释,但就目前而言,仅此而已。
final usersProvider = StateNotifierProvider.autoDispose<UserNotifier, AsyncValue<List<User>>>((ref) { return UserNotifier(ref);});class UserNotifier extends StateNotifier<AsyncValue<List<User>>> { final AutoDisposeStateNotifierProviderRef _ref; late final UserService _service; UserNotifier(this._ref) : super(const AsyncValue.data(<User>[])) { _service = _ref.watch(userService); getUsers(); } Future<void> getUsers() async { state = const AsyncValue.loading(); final res = await AsyncValue.guard(() async => await _service.getUsers()); state = AsyncValue.data(res.asData!.value); }}
创立排序和过滤器提供程序
enum Role { none, normal, admin }enum Sort { normal, reversed }final filterProvider = StateProvider.autoDispose<Role>((_) => Role.none);final sortProvider = StateProvider.autoDispose<Sort>((_) => Sort.normal);
从提供程序获取获取的列表并进行筛选,而后应用其余提供程序对它们进行排序
final filteredAndSortedUsersProvider = Provider.autoDispose.family<List<User>, List<User>>((ref, users) { final filter = ref.watch(filterProvider); final sort = ref.watch(sortProvider); late final List<User> filteredList; switch (filter) { case Role.admin: filteredList = users.where((e) => e.role == Role.admin).toList(); break; case Role.normal: filteredList = users.where((e) => e.role == Role.normal).toList(); break; default: filteredList = users; } switch (sort) { case Sort.normal: return filteredList; case Sort.reversed: return filteredList.reversed.toList(); default: return filteredList; }});
在用户界面中显示所有内容
class HomePage extends ConsumerWidget { const HomePage({Key? key}) : super(key: key); @override Widget build(BuildContext context, WidgetRef ref) { final users = ref.watch(usersProvider); return Scaffold( appBar: AppBar( centerTitle: true, title: const Text('Users'), ), body: RefreshIndicator( onRefresh: () async => await ref.refresh(usersProvider), child: users.when( data: (list) { final newList = ref.watch(filteredAndSortedUsersProvider(list)); if (newList.isEmpty) { return const Center(child: Text('There is no user')); } return ListView.builder( itemCount: newList.length, itemBuilder: (_, i) { final user = newList[i]; return ListTile( minVerticalPadding: 25, leading: Image.network(user.avatar), title: Text('${user.firstName} ${user.lastName}'), trailing: Text(user.role.name), ); }, ); }, error: (_, __) => const Center(child: Text('err')), loading: () => const Center(child: CircularProgressIndicator()), ), ), floatingActionButtonLocation: FloatingActionButtonLocation.centerFloat, floatingActionButton: Row( mainAxisSize: MainAxisSize.min, children: [ Expanded( child: Padding( padding: const EdgeInsets.all(8.0), child: Consumer( builder: (_, ref, __) { final sort = ref.watch(sortProvider.state); return ElevatedButton( onPressed: () { if (sort.state == Sort.reversed) { sort.state = Sort.normal; } else { sort.state = Sort.reversed; } }, child: Text( sort.state == Sort.normal ? 'sort reversed' : 'sort normal', ), ); }, ), ), ), Expanded( child: Padding( padding: const EdgeInsets.all(8.0), child: Consumer( builder: (_, ref, __) { final filter = ref.watch(filterProvider.state); return ElevatedButton( onPressed: () { if (filter.state == Role.admin) { filter.state = Role.none; } else { filter.state = Role.admin; } }, child: Text( filter.state == Role.admin ? 'remove filter' : 'filter admins', ), ); }, ), ), ), ], ), ); }}
完结
如果你把这个例子看作一个电子商务应用程序,那么这个例子就更有意义了
我不是 riverpod
的宗师。只是学习和分享我的教训,所以请如果你晓得一个更好的形式应用 riverpod
请让咱们晓得!
示例 Github 我的项目
这是源代码。
https://github.com/iisprey/ri...
谢谢你的浏览
© 猫哥
- ducafecat.tech
- github
- bilibili