如何用单个Bloc管理单页面15个API状态?求最佳实践
多API场景下的状态管理最佳实践
首页需要调用15个API接口,当前实现是为每个API创建单独的Status抽象类(如Api1Status、Api2Status),并将这些Status作为HomeState的构造参数,通过buildWhen管理组件构建逻辑,但这种方式导致代码冗余、结构复杂。当前核心代码如下:
当前HomeState实现
class HomeState { Api1Status? api1status; Api2Status? api2Status; HomeState({ this.api1status, this.api2Status, }); HomeState copyWith({ Api1Status? newApi1status, Api2Status? newApi2Status, }) { return HomeState( api1status: newApi1status ?? this.api1status, api2Status: newApi2Status ?? this.api2Status, ); } }
当前单个API状态类实现
@immutable abstract class Api1Status{} class Api1Loading extends Api1Status{} class Api1Completed extends Api1Status{ final Api1Entity Api1Entity; Api1Completed(this.Api1Entity); } class Api1Error extends Api1Status{ final String message; Api1Error(this.message); }
优化方案:通用化+结构化处理
1. 用泛型封装通用API状态类
创建一套通用的泛型状态类,替代每个API单独定义的Status,彻底消除重复代码:
@immutable abstract class ApiStatus<T> {} class ApiLoading<T> extends ApiStatus<T> {} class ApiCompleted<T> extends ApiStatus<T> { final T data; ApiCompleted(this.data); } class ApiError<T> extends ApiStatus<T> { final String message; ApiError(this.message); }
2. 优化HomeState结构
根据业务需求选择以下两种结构:
方式一:明确字段的泛型状态(推荐)
适合需要清晰区分每个API状态的场景,比原实现简洁且类型安全:
class HomeState { final ApiStatus<Api1Entity>? api1Status; final ApiStatus<Api2Entity>? api2Status; // ... 其余13个API的泛型状态字段 HomeState({ this.api1Status, this.api2Status, // ... 其余字段初始化 }); HomeState copyWith({ ApiStatus<Api1Entity>? api1Status, ApiStatus<Api2Entity>? api2Status, // ... 其余字段的copy参数 }) { return HomeState( api1Status: api1Status ?? this.api1Status, api2Status: api2Status ?? this.api2Status, // ... 其余字段赋值 ); } }
方式二:Map存储动态状态(适合API数量极多的场景)
如果API数量后续可能持续扩展,用Map存储状态更灵活,同时封装获取方法保证类型安全:
class HomeState { final Map<String, ApiStatus<Object>> apiStates; HomeState({this.apiStates = const {}}); HomeState copyWith({Map<String, ApiStatus<Object>>? apiStates}) { return HomeState( apiStates: {...this.apiStates, ...?apiStates}, ); } // 封装类型安全的状态获取方法 ApiStatus<T>? getApiStatus<T>(String key) { return apiStates[key] as ApiStatus<T>?; } }
使用示例:
// 更新api1为加载状态 state.copyWith(apiStates: {'api1': ApiLoading<Api1Entity>()}); // 更新api1为完成状态 state.copyWith(apiStates: {'api1': ApiCompleted<Api1Entity>(api1Data)});
3. 简化UI层buildWhen逻辑
封装通用的状态对比工具方法,避免每个BlocBuilder重复写判断逻辑:
// 通用判断方法:判断两个API状态是否需要触发重建 bool shouldRebuildApiStatus<T>(ApiStatus<T>? prev, ApiStatus<T>? current) { if (prev.runtimeType != current.runtimeType) return true; if (prev is ApiCompleted<T> && current is ApiCompleted<T>) { return prev.data != current.data; // 需确保实体类重写==运算符 } if (prev is ApiError<T> && current is ApiError<T>) { return prev.message != current.message; } return false; }
在UI层使用:
BlocBuilder<HomeBloc, HomeState>( buildWhen: (prev, current) => shouldRebuildApiStatus(prev.api1Status, current.api1Status), builder: (context, state) { final status = state.api1Status; if (status is ApiLoading) { return const CircularProgressIndicator(); } else if (status is ApiCompleted) { return Text(status.data.title); } else if (status is ApiError) { return Text(status.message); } return const SizedBox(); }, )
4. 进阶优化:拆分状态到子Bloc
如果首页业务模块复杂,可将不同业务域的API拆分到单独子Bloc(如BannerBloc、RecommendBloc),每个子Bloc管理自己的API状态,首页通过MultiBlocBuilder组合多个Bloc,进一步降低单个HomeState的复杂度。
内容的提问来源于stack exchange,提问作者sianami
相关产品推荐
相关产品推荐

