Riverpod 3.0.0(2025 年 9 月发布)是 Flutter 状态管理库的重大更新,简化了 API,引入了"mutations"功能(处理副作用,如加载/错误状态),统一了更新过滤机制(全部使用 ==
比较),并默认支持自动重试失败的 provider。关键更新 :Riverpod 3.0.0 不再强制要求使用 @riverpod
注解和 riverpod_generator
,可以直接编写 Notifier
类,减少 boilerplate 代码。旧版 provider(如 StateProvider
、FutureProvider
等)被标记为遗留(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?(决策流程)
-
数据是同步且只读?
使用 Provider 。
示例:
dart:disable-runfinal configProvider = Provider<String>((ref) => 'Hello');
适用:静态配置、计算值。UI 中使用:
final value = ref.watch(configProvider);
。 -
数据是同步且可变?
使用 NotifierProvider 。
示例:
dartclass Counter extends Notifier<int> { @override int build() => 0; // 初始状态 void increment() => state++; // 修改状态 } final counterProvider = NotifierProvider<Counter, int>(() => Counter());
适用:计数器、表单输入。UI 中使用:
final count = ref.watch(counterProvider);
。 -
数据是异步(Future)且可能需要更新?
使用 AsyncNotifierProvider 。
示例:
dartclass 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);
。 -
数据是流式(Stream)且实时更新?
使用 StreamNotifierProvider 。
示例:
dartclass MessageStream extends StreamNotifier<List<Message>> { @override Stream<List<Message>> build() => firestore.collection('messages').snapshots(); } final messageProvider = StreamNotifierProvider<MessageStream, List<Message>>((ref) => MessageStream());
适用:实时数据(如 Firestore 流、WebSocket)。
-
复杂业务逻辑或副作用?
使用 mutations (3.0 新功能)。
示例:
dartfinal submitMutation = mutationProvider((ref, FormData data) async { await api.submit(data); });
适用:表单提交、一次性操作,显示加载/错误状态而不中断 provider。
-
遗留类型?
仅用于迁移旧代码,逐步替换为 Notifier 系列。
@riverpod
注解可选,若使用可运行flutter packages pub run build_runner build
生成代码。
最佳实践
- 无需注解 :Riverpod 3.0.0 允许直接编写
Notifier
/AsyncNotifier
类,无需@riverpod
和riverpod_generator
,但仍支持代码生成以减少 boilerplate。 - 修饰符 :
.autoDispose
:自动清理未使用的 provider,防止内存泄漏。.family
:参数化 provider(如userProvider.family(userId)
)。
- 测试:Notifier 类可独立测试,无需 Flutter 环境。
- 性能 :更新过滤统一使用
==
,减少不必要重建。 - 错误处理 :异步 provider 抛
ProviderException
,支持自动重试。 - 迁移:从 2.x 迁移时,替换遗留 provider,检查错误处理逻辑。