Riverpod 从 StateNotifier 迁移到 Notifier/AsyncNotifier 完全指南
前言
在 Riverpod 2.0 版本中,引入了全新的 Notifier
和 AsyncNotifier
类,它们旨在替代原有的 StateNotifier
。本文将深入探讨如何从 StateNotifier
迁移到这些新 API,并分析新 API 带来的优势和使用场景。
新旧 API 对比
基础用法对比
让我们先看一个典型的 StateNotifier
实现:
class CounterNotifier extends StateNotifier<int> {
CounterNotifier() : super(0);
void increment() => state++;
}
final counterProvider = StateNotifierProvider<CounterNotifier, int>((ref) {
return CounterNotifier();
});
迁移到 Notifier
后的等效实现:
class CounterNotifier extends Notifier<int> {
@override
int build() {
return 0;
}
void increment() {
state++;
}
}
final counterProvider = NotifierProvider<CounterNotifier, int>(CounterNotifier.new);
主要差异点
-
初始化逻辑集中化:
StateNotifier
的初始化分散在构造函数和 provider 中Notifier
将所有初始化逻辑集中在build
方法中
-
依赖声明位置:
StateNotifier
的依赖在 provider 中声明Notifier
的依赖在build
方法中通过ref
获取
-
构造函数简化:
Notifier
的构造函数通常为空或非常简单
异步状态管理迁移
旧版异步实现
class UserNotifier extends StateNotifier<AsyncValue<User>> {
UserNotifier(this.userId) : super(const AsyncValue.loading()) {
_fetchUser();
}
final String userId;
Future<void> _fetchUser() async {
state = const AsyncValue.loading();
state = await AsyncValue.guard(() => fetchUser(userId));
}
}
新版 AsyncNotifier 实现
class UserNotifier extends AsyncNotifier<User> {
@override
Future<User> build() async {
return fetchUser(arg);
}
Future<void> refreshUser() async {
state = const AsyncValue.loading();
state = await AsyncValue.guard(() => fetchUser(arg));
}
}
异步迁移要点
- 初始化逻辑完全移至
build
方法 - 不再需要手动处理
try/catch
块 AsyncValue.guard
会自动转换 Future 为 AsyncValue- 状态更新更加直观简洁
高级特性对比
家族参数和自动销毁
旧版 StateNotifier
处理家族参数和自动销毁:
class BugsEncounteredNotifier extends StateNotifier<int> {
BugsEncounteredNotifier(this.userId, this._repo) : super(0);
final String userId;
final BugsRepository _repo;
Future<void> addBug(Bug bug) async {
await _repo.addBug(userId, bug);
state++;
}
}
final bugsEncounteredProvider = StateNotifierProvider.autoDispose
.family<BugsEncounteredNotifier, int, String>((ref, userId) {
final repo = ref.watch(bugsRepositoryProvider);
return BugsEncounteredNotifier(userId, repo);
});
新版实现:
class BugsEncounteredNotifier extends AutoDisposeFamilyAsyncNotifier<int, String> {
@override
Future<int> build(String arg) async {
final repo = ref.watch(bugsRepositoryProvider);
return repo.countBugs(arg);
}
Future<void> addBug(Bug bug) async {
await ref.read(bugsRepositoryProvider).addBug(arg, bug);
state = AsyncValue.data((state as AsyncData).value + 1);
}
}
final bugsEncounteredProvider = AsyncNotifierProvider.autoDispose
.family<BugsEncounteredNotifier, int, String>(BugsEncounteredNotifier.new);
生命周期管理
旧版生命周期管理:
class MyNotifier extends StateNotifier<int> {
MyNotifier(this.duration) : super(0) {
_timer = Timer.periodic(duration, (_) => state++);
}
final Duration duration;
late final Timer _timer;
@override
void dispose() {
_timer.cancel();
super.dispose();
}
}
新版生命周期管理:
class MyNotifier extends Notifier<int> {
@override
int build() {
final duration = ref.watch(durationProvider);
final timer = Timer.periodic(duration, (_) => state++);
ref.onDispose(() => timer.cancel());
return 0;
}
}
测试相关变更
测试状态访问
旧版测试方式:
test('test notifier', () {
final notifier = MyNotifier();
expect(notifier.debugState, 0);
});
新版测试方式:
test('test notifier', () async {
final container = ProviderContainer();
addTearDown(container.dispose);
final notifier = container.read(myNotifierProvider.notifier);
expect(container.read(myNotifierProvider), 0);
});
迁移建议
- 逐步迁移:可以先从简单的状态管理开始迁移
- 优先处理异步场景:
AsyncNotifier
带来的改进最为显著 - 注意生命周期差异:新版生命周期管理更加集中和一致
- 利用代码生成:新版 API 设计考虑了对代码生成的支持
结语
Riverpod 2.0 引入的 Notifier
和 AsyncNotifier
提供了更加统一、简洁的 API 设计,特别是在异步状态管理方面带来了显著的改进。通过本文的对比和示例,开发者可以清晰地了解如何从 StateNotifier
迁移到新 API,并充分利用新特性提升开发体验和代码质量。
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考