原文
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';
@freezed
class 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