如何在Riverpod 2.0的AsyncNotifierProvider中获取列表子集
Riverpod 2.0 复用全量Todo数据实现已完成列表筛选
你当前在Widget的build方法中过滤已完成Todo的方式,确实存在复用性不足、测试不便以及渲染优化空间有限的问题。下面提供两种在Provider层实现筛选的方案,均基于主asyncTodosProvider的全量数据:
方案一:使用FutureProvider(轻量筛选场景)
对于仅需简单筛选的场景,FutureProvider是最简洁的选择,无需额外编写Notifier类,直接依赖主Provider完成数据转换:
// 定义筛选已完成Todo的Provider final completedTodosProvider = FutureProvider<List<Todo>>((ref) async { // 监听全量Todo数据,自动获取最新状态 final asyncTodos = await ref.watch(asyncTodosProvider.future); // 执行筛选逻辑 return asyncTodos.where((todo) => todo.completed).toList(); });
在Widget中使用该Provider:
class CompletedTodoListView extends ConsumerWidget { const CompletedTodoListView({Key? key}) : super(key: key); @override Widget build(BuildContext context, WidgetRef ref) { final asyncCompletedTodos = ref.watch(completedTodosProvider); return asyncCompletedTodos.when( data: (completedTodos) => ListView.builder( itemCount: completedTodos.length, itemBuilder: (context, index) { final todo = completedTodos[index]; return ListTile(title: Text(todo.description)); }, ), loading: () => const Center(child: CircularProgressIndicator()), error: (err, stack) => Text('加载失败: $err'), ); } }
优势:代码量极少,逻辑直接,无需维护额外状态类,适合快速实现简单筛选需求。
方案二:使用AsyncNotifierProvider(可扩展场景)
如果后续需要对筛选后的Todo列表添加CRUD操作、刷新逻辑或其他复杂处理,推荐使用AsyncNotifierProvider,将筛选逻辑封装在独立的Notifier中,提升可维护性和可测试性:
class CompletedTodosNotifier extends AsyncNotifier<List<Todo>> { @override Future<List<Todo>> build() async { // 依赖主Provider获取全量Todo数据 final allTodos = await ref.watch(asyncTodosProvider.future); // 执行筛选 return _filterCompletedTodos(allTodos); } // 封装筛选逻辑,便于测试和复用 List<Todo> _filterCompletedTodos(List<Todo> todos) { return todos.where((todo) => todo.completed).toList(); } // 可添加扩展方法,比如手动刷新筛选结果 Future<void> refreshCompletedTodos() async { // 触发主Provider刷新全量数据 await ref.read(asyncTodosProvider.notifier).build(); // 重新执行筛选逻辑 state = const AsyncValue.loading(); final allTodos = await ref.watch(asyncTodosProvider.future); state = AsyncValue.data(_filterCompletedTodos(allTodos)); } } // 定义对应的Provider final completedTodosProvider = AsyncNotifierProvider<CompletedTodosNotifier, List<Todo>>(() { return CompletedTodosNotifier(); });
Widget中的使用方式和方案一一致,同时还可以调用扩展方法:
// 比如在按钮点击时刷新 ElevatedButton( onPressed: () => ref.read(completedTodosProvider.notifier).refreshCompletedTodos(), child: const Text('刷新已完成列表'), )
优势:逻辑封装更彻底,支持扩展自定义方法,便于单元测试(可单独测试_filterCompletedTodos方法),适合复杂业务场景。
两种方案对比
| 方案类型 | 适用场景 | 优势 | 不足 |
|---|---|---|---|
| FutureProvider | 简单筛选、无扩展需求 | 代码简洁、快速实现 | 不支持自定义方法、逻辑分散 |
| AsyncNotifierProvider | 复杂逻辑、需扩展操作 | 可维护性强、可测试性好 | 代码量稍多、需维护Notifier |
内容的提问来源于stack exchange,提问作者Robin
相关产品推荐
相关产品推荐

