如何用Riverpod与Freezed合并两个API请求状态?
合并两个API请求状态的实现方案
针对你需要合并两个API请求状态的需求,这里提供一套基于Riverpod和Freezed的实现方案,完全匹配你要求的逻辑:双请求都成功才触发成功状态,任一失败则进入错误状态,其余情况保持加载。
1. 定义合并后的全局状态类
首先创建一个Freezed状态类,用来表示两个API请求的整体状态,成功状态需要同时持有两个接口返回的实体:
import "package:freezed_annotation/freezed_annotation.dart"; import "...features/profile/domain/entities/user_profile_entity.dart"; import "...features/profile/domain/entities/user_properties_entity.dart"; part "combined_profile_state.freezed.dart"; @freezed class CombinedProfileState with _$CombinedProfileState { /// 初始状态 const factory CombinedProfileState.initial() = _CombinedProfileStateInitial; /// 加载中(任一请求未完成) const factory CombinedProfileState.loading() = _CombinedProfileStateLoading; /// 双请求均成功 const factory CombinedProfileState.success({ required ProfileEntity profile, required UserPropertiesEntity properties, }) = _CombinedProfileStateSuccess; /// 任一请求失败 const factory CombinedProfileState.error([String? message]) = _CombinedProfileStateError; }
2. 创建组合状态Provider
通过Riverpod的Provider监听两个子Notifier的状态变化,实时推导整体状态:
import "package:riverpod_annotation/riverpod_annotation.dart"; import "user_profile_details_notifier.dart"; import "user_properties_notifier.dart"; import "combined_profile_state.dart"; part "combined_profile_provider.g.dart"; @riverpod CombinedProfileState combinedProfile(CombinedProfileRef ref) { // 监听两个子状态的实时变化 final profileState = ref.watch(userProfileDetailsNotifierProvider); final propertiesState = ref.watch(userPropertiesNotifierProvider); // 检查是否有请求出错 final profileError = profileState.maybeWhen( error: (msg) => msg, orElse: () => null, ); final propertiesError = propertiesState.maybeWhen( error: (msg) => msg, orElse: () => null, ); if (profileError != null) { return CombinedProfileState.error(profileError); } if (propertiesError != null) { return CombinedProfileState.error(propertiesError); } // 检查是否两个请求都返回了有效数据 final profileData = profileState.maybeWhen( data: (profile) => profile, orElse: () => null, ); final propertiesData = propertiesState.maybeWhen( data: (props) => props, orElse: () => null, ); if (profileData != null && propertiesData != null) { return CombinedProfileState.success( profile: profileData, properties: propertiesData, ); } // 其余情况(初始、单个请求加载中)返回加载状态 return const CombinedProfileState.loading(); }
3. 页面中使用组合状态
在页面Widget中直接监听这个组合Provider,根据整体状态渲染对应UI:
class ProfilePage extends ConsumerWidget { const ProfilePage({super.key}); @override Widget build(BuildContext context, WidgetRef ref) { final combinedState = ref.watch(combinedProfileProvider); return combinedState.when( initial: () => const SizedBox.shrink(), loading: () => const Center(child: CircularProgressIndicator()), success: (profile, properties) { // 渲染成功页面,使用两个接口返回的数据 return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text("用户名:${profile.name}"), Text("账户设置:${properties.settings}"), // 其他UI元素 ], ); }, error: (msg) { return Center(child: Text(msg ?? "加载失败,请重试")); }, ); } }
4. 保留原有Token失效逻辑
你原代码中的TokenFailure处理逻辑无需修改,两个子Notifier中已经实现了Token失效时的登出操作,组合状态会自动感知到错误状态,但登出逻辑已经在子Notifier中独立完成。
额外说明
- 两个子Notifier的
build方法中自动发起请求的逻辑保持不变,页面初始化时两个API会同时触发请求。 - 组合状态会自动响应任一子状态的变化,实时更新整体状态,无需手动触发刷新。
内容的提问来源于stack exchange,提问作者patana93
相关产品推荐
相关产品推荐

