Riverpod 3.0.0 版本中 Provider 类型选择指南

Riverpod 3.0.0(2025 年 9 月发布)是 Flutter 状态管理库的重大更新,简化了 API,引入了"mutations"功能(处理副作用,如加载/错误状态),统一了更新过滤机制(全部使用 == 比较),并默认支持自动重试失败的 provider。关键更新 :Riverpod 3.0.0 不再强制要求使用 @riverpod 注解和 riverpod_generator,可以直接编写 Notifier 类,减少 boilerplate 代码。旧版 provider(如 StateProviderFutureProvider 等)被标记为遗留(legacy) ,需从 flutter_riverpod/legacy.dart 导入,官方推荐迁移到基于 Notifier 的新 provider 类型。这些新类型更统一、可测试,且支持手动编写或代码生成(仍可选 @riverpod)。

选择 provider 时,考虑以下因素:

  • 同步 vs 异步:数据是立即可用(同步)还是需要等待(Future/Stream)?
  • 只读 vs 可变:状态是否需要外部修改?
  • 复杂逻辑:是否涉及业务规则、依赖注入或副作用?
  • 性能与清理 :是否需要 .autoDispose(自动销毁未使用的 provider)或 .family(参数化 provider)修饰符?

以下是 Riverpod 3.0.0 中推荐的 provider 类型及选择指南,遗留类型仅作迁移参考。内容基于官方文档和社区实践。

Riverpod 3.0.0 Provider 类型选择指南

主要 Provider 类型

Provider 类型 描述与用途 适用场景示例 优缺点简析
Provider 只读同步 provider,返回固定或计算值。不支持状态修改。 常量配置、简单计算(如字符串格式化)、依赖注入。 优点 :轻量、易缓存;缺点:不可变,无法处理异步。
NotifierProvider<T, Notifier> 可变同步状态,使用 Notifier 类管理内部状态。支持 state 更新。 计数器、表单输入、简单 UI 状态(如开关)。 优点 :简单、可测试;缺点:不适合复杂异步逻辑。推荐用于简单可变状态。
AsyncNotifierProvider<T, AsyncNotifier<T, T>> 可变异步状态,使用 AsyncNotifier 处理 Future 值。内置加载/错误/数据状态。 API 调用、数据库查询,需要更新异步数据。 优点 :统一处理异步(loading/error),支持 mutations;缺点:稍复杂。推荐用于大多数异步场景。
StreamNotifierProvider<T, StreamNotifier<T, T>> 可变流式状态,使用 StreamNotifier 处理 Stream 值。实时更新。 实时数据(如 WebSocket、动画流)、事件监听。 优点 :响应式流处理;缺点:仅限 Stream 数据。推荐用于实时更新。
遗留:StateProvider (从 legacy.dart) 简单可变状态(如字符串/整数)。不推荐。 临时简单状态(迁移时使用)。 优点 :快速;缺点:缺乏类型安全,官方弃用。迁移到 NotifierProvider。
遗留:FutureProvider (从 legacy.dart) 只读异步 Future 值。不推荐。 一次性异步加载(迁移时使用)。 优点 :简单异步;缺点:不可变、无内置重试。迁移到 AsyncNotifierProvider。
遗留:StreamProvider (从 legacy.dart) 只读流式 Stream 值。不推荐。 实时流(迁移时使用)。 优点 :流支持;缺点:不可变。迁移到 StreamNotifierProvider。
遗留:StateNotifierProvider<T, S> (从 legacy.dart) 复杂可变状态,使用 StateNotifier 类。不推荐。 业务逻辑类(如用户认证)。 优点 :强大;缺点:冗余。迁移到 NotifierProvider(简化版)。

如何选择 Provider?(决策流程)

  1. 数据是同步且只读?

    使用 Provider

    示例:

    dart:disable-run 复制代码
    final configProvider = Provider<String>((ref) => 'Hello');

    适用:静态配置、计算值。UI 中使用:final value = ref.watch(configProvider);

  2. 数据是同步且可变?

    使用 NotifierProvider

    示例:

    dart 复制代码
    class Counter extends Notifier<int> {
      @override
      int build() => 0;  // 初始状态
      void increment() => state++;  // 修改状态
    }
    final counterProvider = NotifierProvider<Counter, int>(() => Counter());

    适用:计数器、表单输入。UI 中使用:final count = ref.watch(counterProvider);

  3. 数据是异步(Future)且可能需要更新?

    使用 AsyncNotifierProvider

    示例:

    dart 复制代码
    class UserData extends AsyncNotifier<User> {
      @override
      Future<User> build(String userId) async {
        return await fetchUser(userId);  // 异步加载
      }
      Future<void> refresh() async => state = const AsyncLoading();  // 更新
    }
    final userProvider = AsyncNotifierProvider<UserData, User>((ref) => UserData());

    适用:API 调用、数据库查询。自动处理 AsyncValue(loading/data/error)。UI 中使用:final user = ref.watch(userProvider);

  4. 数据是流式(Stream)且实时更新?

    使用 StreamNotifierProvider

    示例:

    dart 复制代码
    class MessageStream extends StreamNotifier<List<Message>> {
      @override
      Stream<List<Message>> build() => firestore.collection('messages').snapshots();
    }
    final messageProvider = StreamNotifierProvider<MessageStream, List<Message>>((ref) => MessageStream());

    适用:实时数据(如 Firestore 流、WebSocket)。

  5. 复杂业务逻辑或副作用?

    使用 mutations (3.0 新功能)。

    示例:

    dart 复制代码
    final submitMutation = mutationProvider((ref, FormData data) async {
      await api.submit(data);
    });

    适用:表单提交、一次性操作,显示加载/错误状态而不中断 provider。

  6. 遗留类型?

    仅用于迁移旧代码,逐步替换为 Notifier 系列。@riverpod 注解可选,若使用可运行 flutter packages pub run build_runner build 生成代码。

最佳实践

  • 无需注解 :Riverpod 3.0.0 允许直接编写 Notifier/AsyncNotifier 类,无需 @riverpodriverpod_generator,但仍支持代码生成以减少 boilerplate。
  • 修饰符
    • .autoDispose:自动清理未使用的 provider,防止内存泄漏。
    • .family:参数化 provider(如 userProvider.family(userId))。
  • 测试:Notifier 类可独立测试,无需 Flutter 环境。
  • 性能 :更新过滤统一使用 ==,减少不必要重建。
  • 错误处理 :异步 provider 抛 ProviderException,支持自动重试。
  • 迁移:从 2.x 迁移时,替换遗留 provider,检查错误处理逻辑。
相关推荐
ZFJ_张福杰6 小时前
【区块链】Fiat24 深度解读(含 Flutter 集成与 SDK 骨架)
flutter·web3·区块链·钱包
古希腊被code拿捏的神6 小时前
【Flutter】抽象类的运用(abstract与implements的实践)
flutter
ZFJ_张福杰6 小时前
【Flutter】GetX最佳实践与避坑指南
android·flutter·ios·getx
wuhanwhite2 天前
Flutter Release 打包后插件失效问题排查与解决(实战分享)
flutter
BG2 天前
Flutter Svg转Path对象,path.getBounds()获取测量信息不准问题记录
flutter
MaoJiu2 天前
Flutter中实现Hero Page Route效果
flutter
神经骚栋2 天前
Flutter面试题01-Flutter中的三棵树
flutter·面试
小严家3 天前
Flutter完整开发指南 | Flutter&Dart – The Complete Guide
开发语言·flutter
倾云鹤3 天前
flutter实现Function Call
flutter·llm·function call