You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.28 18:07:14